Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
17b5a358
Commit
17b5a358
authored
Apr 26, 2008
by
Hanno Schlichting
Browse files
Options
Browse Files
Download
Plain Diff
Merged philikon-aq branch into trunk, yeah!
parents
d6687526
010ab27a
Changes
59
Hide whitespace changes
Inline
Side-by-side
Showing
59 changed files
with
2069 additions
and
752 deletions
+2069
-752
doc/CHANGES.txt
doc/CHANGES.txt
+5
-1
lib/python/AccessControl/ImplPython.py
lib/python/AccessControl/ImplPython.py
+9
-18
lib/python/AccessControl/Owned.py
lib/python/AccessControl/Owned.py
+5
-5
lib/python/AccessControl/Permission.py
lib/python/AccessControl/Permission.py
+2
-2
lib/python/AccessControl/PermissionMapping.py
lib/python/AccessControl/PermissionMapping.py
+1
-1
lib/python/AccessControl/Role.py
lib/python/AccessControl/Role.py
+4
-4
lib/python/AccessControl/User.py
lib/python/AccessControl/User.py
+21
-22
lib/python/AccessControl/cAccessControl.c
lib/python/AccessControl/cAccessControl.c
+2
-6
lib/python/Acquisition/_Acquisition.c
lib/python/Acquisition/_Acquisition.c
+263
-89
lib/python/Acquisition/tests.py
lib/python/Acquisition/tests.py
+506
-15
lib/python/App/FactoryDispatcher.py
lib/python/App/FactoryDispatcher.py
+2
-2
lib/python/OFS/FindSupport.py
lib/python/OFS/FindSupport.py
+5
-13
lib/python/OFS/PropertySheets.py
lib/python/OFS/PropertySheets.py
+12
-11
lib/python/OFS/SimpleItem.py
lib/python/OFS/SimpleItem.py
+6
-4
lib/python/OFS/Traversable.py
lib/python/OFS/Traversable.py
+9
-7
lib/python/OFS/ZDOM.py
lib/python/OFS/ZDOM.py
+10
-8
lib/python/Products/Five/bbb.py
lib/python/Products/Five/bbb.py
+25
-3
lib/python/Products/Five/browser/__init__.py
lib/python/Products/Five/browser/__init__.py
+20
-4
lib/python/Products/Five/browser/absoluteurl.py
lib/python/Products/Five/browser/absoluteurl.py
+73
-16
lib/python/Products/Five/browser/adding.py
lib/python/Products/Five/browser/adding.py
+22
-9
lib/python/Products/Five/browser/configure.zcml
lib/python/Products/Five/browser/configure.zcml
+20
-4
lib/python/Products/Five/browser/metaconfigure.py
lib/python/Products/Five/browser/metaconfigure.py
+25
-35
lib/python/Products/Five/browser/pagetemplatefile.py
lib/python/Products/Five/browser/pagetemplatefile.py
+64
-65
lib/python/Products/Five/browser/providerexpression.py
lib/python/Products/Five/browser/providerexpression.py
+23
-14
lib/python/Products/Five/browser/resource.py
lib/python/Products/Five/browser/resource.py
+31
-103
lib/python/Products/Five/browser/tests/aqlegacy.py
lib/python/Products/Five/browser/tests/aqlegacy.py
+147
-0
lib/python/Products/Five/browser/tests/aqlegacy.zcml
lib/python/Products/Five/browser/tests/aqlegacy.zcml
+142
-0
lib/python/Products/Five/browser/tests/aqlegacy_ftest.txt
lib/python/Products/Five/browser/tests/aqlegacy_ftest.txt
+204
-0
lib/python/Products/Five/browser/tests/legacymanager.pt
lib/python/Products/Five/browser/tests/legacymanager.pt
+1
-0
lib/python/Products/Five/browser/tests/legacyprovider.pt
lib/python/Products/Five/browser/tests/legacyprovider.pt
+1
-0
lib/python/Products/Five/browser/tests/pages.py
lib/python/Products/Five/browser/tests/pages.py
+6
-1
lib/python/Products/Five/browser/tests/pages.txt
lib/python/Products/Five/browser/tests/pages.txt
+20
-14
lib/python/Products/Five/browser/tests/pages.zcml
lib/python/Products/Five/browser/tests/pages.zcml
+7
-0
lib/python/Products/Five/browser/tests/pages_ftest.txt
lib/python/Products/Five/browser/tests/pages_ftest.txt
+8
-0
lib/python/Products/Five/browser/tests/provider.txt
lib/python/Products/Five/browser/tests/provider.txt
+2
-5
lib/python/Products/Five/browser/tests/resource_ftest.txt
lib/python/Products/Five/browser/tests/resource_ftest.txt
+34
-12
lib/python/Products/Five/browser/tests/template_variables.pt
lib/python/Products/Five/browser/tests/template_variables.pt
+2
-2
lib/python/Products/Five/browser/tests/test_absoluteurl.py
lib/python/Products/Five/browser/tests/test_absoluteurl.py
+5
-7
lib/python/Products/Five/browser/tests/test_pages.py
lib/python/Products/Five/browser/tests/test_pages.py
+3
-42
lib/python/Products/Five/component/__init__.py
lib/python/Products/Five/component/__init__.py
+1
-1
lib/python/Products/Five/doc/manual.txt
lib/python/Products/Five/doc/manual.txt
+0
-7
lib/python/Products/Five/form/objectwidget.py
lib/python/Products/Five/form/objectwidget.py
+8
-17
lib/python/Products/Five/formlib/formbase.py
lib/python/Products/Five/formlib/formbase.py
+1
-2
lib/python/Products/Five/i18n.py
lib/python/Products/Five/i18n.py
+6
-2
lib/python/Products/Five/site/tests/test_utility.py
lib/python/Products/Five/site/tests/test_utility.py
+4
-4
lib/python/Products/Five/viewlet/README.txt
lib/python/Products/Five/viewlet/README.txt
+8
-9
lib/python/Products/Five/viewlet/directives.txt
lib/python/Products/Five/viewlet/directives.txt
+0
-4
lib/python/Products/Five/viewlet/manager.py
lib/python/Products/Five/viewlet/manager.py
+2
-8
lib/python/Products/Five/viewlet/viewlet.py
lib/python/Products/Five/viewlet/viewlet.py
+12
-13
lib/python/Products/PageTemplates/PageTemplateFile.py
lib/python/Products/PageTemplates/PageTemplateFile.py
+9
-7
lib/python/Products/PageTemplates/ZopePageTemplate.py
lib/python/Products/PageTemplates/ZopePageTemplate.py
+9
-6
lib/python/Shared/DC/Scripts/Bindings.py
lib/python/Shared/DC/Scripts/Bindings.py
+16
-8
lib/python/ZPublisher/BaseRequest.py
lib/python/ZPublisher/BaseRequest.py
+14
-10
lib/python/ZPublisher/HTTPRequest.py
lib/python/ZPublisher/HTTPRequest.py
+5
-2
lib/python/ZPublisher/mapply.py
lib/python/ZPublisher/mapply.py
+10
-21
lib/python/ZPublisher/tests/testBaseRequest.py
lib/python/ZPublisher/tests/testBaseRequest.py
+60
-4
lib/python/ZPublisher/tests/testHTTPRequest.py
lib/python/ZPublisher/tests/testHTTPRequest.py
+47
-69
lib/python/ZPublisher/tests/test_mapply.py
lib/python/ZPublisher/tests/test_mapply.py
+98
-0
lib/python/Zope2/App/startup.py
lib/python/Zope2/App/startup.py
+12
-14
No files found.
doc/CHANGES.txt
View file @
17b5a358
...
...
@@ -78,7 +78,11 @@ Zope Changes
Features added
- Zope2 startup: Zope will now send DatabaseOpened and
- Acquisition has been made aware of __parent__ pointers. This allows
direct access to many Zope 3 classes without the need to mixin
Acquisition base classes for the security to work.
- Zope2 startup: Zope will now send DatabaseOpened and
ProcessStarting events.
- Testing.ZopeTestCase: Introduced a "ZopeLite" test layer, making it
...
...
lib/python/AccessControl/ImplPython.py
View file @
17b5a358
...
...
@@ -17,10 +17,8 @@ import os
import
string
from
logging
import
getLogger
from
Acquisition
import
aq_base
from
Acquisition
import
aq_parent
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_base
,
aq_parent
,
aq_inner
,
aq_acquire
from
Acquisition
import
aq_inContextOf
from
ExtensionClass
import
Base
from
zope.interface
import
implements
...
...
@@ -98,10 +96,10 @@ def rolesForPermissionOn(perm, object, default=_default_roles, n=None):
else
:
r
=
r
+
list
(
roles
)
object
=
getattr
(
object
,
'aq_inner'
,
None
)
object
=
aq_inner
(
object
)
if
object
is
None
:
break
object
=
object
.
aq_parent
object
=
aq_parent
(
object
)
if
r
is
None
:
if
_embed_permission_in_roles
:
...
...
@@ -295,7 +293,7 @@ class ZopeSecurityPolicy:
raise
Unauthorized
(
name
,
value
)
else
:
# Try to acquire roles
try
:
roles
=
container
.
aq_acquire
(
'__roles__'
)
try
:
roles
=
aq_acquire
(
container
,
'__roles__'
)
except
AttributeError
:
if
containerbase
is
not
accessedbase
:
if
self
.
_verbose
:
...
...
@@ -840,17 +838,10 @@ def verifyAcquisitionContext(user, object, object_roles=None):
# This is a strange rule, though
# it doesn't cause any security holes. SDH
return
1
if
not
hasattr
(
object
,
'aq_inContextOf'
):
if
hasattr
(
object
,
'im_self'
):
# This is a method. Grab its self.
object
=
object
.
im_self
if
not
hasattr
(
object
,
'aq_inContextOf'
):
# object is not wrapped, therefore we
# can't determine context.
# Fail the access attempt. Otherwise
# this would be a security hole.
return
None
if
not
object
.
aq_inContextOf
(
ucontext
,
1
):
if
hasattr
(
object
,
'im_self'
):
# This is a method. Grab its self.
object
=
object
.
im_self
if
not
aq_inContextOf
(
object
,
ucontext
,
1
):
if
'Shared'
in
object_roles
:
# Old role setting. Waaa
object_roles
=
user
.
_shared_roles
(
object
)
...
...
lib/python/AccessControl/Owned.py
View file @
17b5a358
...
...
@@ -21,7 +21,7 @@ from AccessControl import ClassSecurityInfo
from
AccessControl
import
getSecurityManager
,
Unauthorized
from
AccessControl.Permissions
import
view_management_screens
from
AccessControl.Permissions
import
take_ownership
from
Acquisition
import
aq_get
,
aq_parent
,
aq_base
from
Acquisition
import
aq_get
,
aq_parent
,
aq_base
,
aq_inner
from
requestmethod
import
requestmethod
from
zope.interface
import
implements
...
...
@@ -236,12 +236,12 @@ class Owned(ExtensionClass.Base):
def
manage_fixupOwnershipAfterAdd
(
self
):
# Sigh, get the parent's _owner
parent
=
getattr
(
self
,
'
aq_parent
'
,
None
)
parent
=
getattr
(
self
,
'
__parent__
'
,
None
)
if
parent
is
not
None
:
_owner
=
aq_get
(
parent
,
'_owner'
,
None
,
1
)
else
:
_owner
=
None
if
(
_owner
is
None
and
((
not
hasattr
(
self
,
'aq_parent'
)
)
or
((
getattr
(
self
,
'__parent__'
,
None
)
is
None
)
or
(
not
hasattr
(
self
,
'getPhysicalRoot'
))
)
):
...
...
@@ -298,13 +298,13 @@ def ownerInfo(user, getattr=getattr):
return
None
uid
=
user
.
getId
()
if
uid
is
None
:
return
uid
db
=
user
.
aq_inner
.
aq_parent
db
=
aq_parent
(
aq_inner
(
user
))
path
=
[
absattr
(
db
.
id
)]
root
=
db
.
getPhysicalRoot
()
while
1
:
db
=
getattr
(
db
,
'aq_inner'
,
None
)
if
db
is
None
:
break
db
=
db
.
aq_parent
db
=
aq_parent
(
db
)
if
db
is
root
:
break
id
=
db
.
id
if
not
isinstance
(
id
,
str
):
...
...
lib/python/AccessControl/Permission.py
View file @
17b5a358
...
...
@@ -17,6 +17,7 @@ $Id$
import
string
,
Products
,
Globals
from
Acquisition
import
aq_base
name_trans
=
filter
(
lambda
c
,
an
=
string
.
letters
+
string
.
digits
+
'_'
:
c
not
in
an
,
map
(
chr
,
range
(
256
)))
...
...
@@ -36,8 +37,7 @@ class Permission:
self
.
name
=
name
self
.
_p
=
'_'
+
string
.
translate
(
name
,
name_trans
)
+
"_Permission"
self
.
data
=
data
if
hasattr
(
obj
,
'aq_base'
):
obj
=
obj
.
aq_base
self
.
obj
=
obj
self
.
obj
=
aq_base
(
obj
)
self
.
default
=
default
def
getRoles
(
self
,
default
=
_marker
):
...
...
lib/python/AccessControl/PermissionMapping.py
View file @
17b5a358
...
...
@@ -105,7 +105,7 @@ class RoleManager:
return
r
def
_isBeingAccessedAsZClassDefinedInstanceMethod
(
self
):
p
=
getattr
(
self
,
'
aq_parent
'
,
None
)
p
=
getattr
(
self
,
'
__parent__
'
,
None
)
if
p
is
None
:
return
0
# Not wrapped
base
=
getattr
(
p
,
'aq_base'
,
None
)
return
type
(
base
)
is
PermissionMapper
...
...
lib/python/AccessControl/Role.py
View file @
17b5a358
...
...
@@ -188,7 +188,7 @@ class RoleManager(ExtensionClass.Base, PermissionMapping.RoleManager):
if
userObj
:
break
else
:
current
=
current
.
aq_parent
current
=
current
.
__parent__
newSecurityManager
(
None
,
userObj
)
# necessary?
...
...
@@ -414,7 +414,7 @@ class RoleManager(ExtensionClass.Base, PermissionMapping.RoleManager):
raise
OverflowError
for
name
in
unl
:
dict
[
name
]
=
1
item
=
getattr
(
item
,
'
aq_parent
'
,
_notfound
)
item
=
getattr
(
item
,
'
__parent__
'
,
_notfound
)
if
item
is
_notfound
:
break
keys
=
dict
.
keys
()
...
...
@@ -511,9 +511,9 @@ class RoleManager(ExtensionClass.Base, PermissionMapping.RoleManager):
for
role
in
roles
:
if
not
dup
(
role
):
dict
[
role
]
=
1
if
not
hasattr
(
obj
,
'aq_parent'
)
:
if
getattr
(
obj
,
'__parent__'
,
None
)
is
None
:
break
obj
=
obj
.
aq_parent
obj
=
obj
.
__parent__
x
=
x
+
1
roles
=
dict
.
keys
()
roles
.
sort
()
...
...
lib/python/AccessControl/User.py
View file @
17b5a358
...
...
@@ -20,6 +20,9 @@ import re
import
socket
from
base64
import
decodestring
from
Acquisition
import
aq_base
from
Acquisition
import
aq_parent
from
Acquisition
import
aq_inContextOf
from
Acquisition
import
Implicit
from
App.Management
import
Navigation
,
Tabs
from
Globals
import
DTMLFile
,
MessageDialog
,
Persistent
,
PersistentMapping
...
...
@@ -106,7 +109,7 @@ class BasicUser(Implicit):
for
r
in
dict
.
get
(
userid
,
[]):
local
[
r
]
=
1
inner
=
getattr
(
object
,
'aq_inner'
,
object
)
parent
=
getattr
(
inner
,
'
aq_parent
'
,
None
)
parent
=
getattr
(
inner
,
'
__parent__
'
,
None
)
if
parent
is
not
None
:
object
=
parent
continue
...
...
@@ -148,10 +151,10 @@ class BasicUser(Implicit):
else
:
try
:
return
r
+
list
(
roles
)
except
:
return
r
if
hasattr
(
parent
,
'aq_parent'
)
:
if
getattr
(
parent
,
'__parent__'
,
None
)
is
not
None
:
while
hasattr
(
parent
.
aq_self
,
'aq_self'
):
parent
=
parent
.
aq_self
parent
=
parent
.
aq_parent
parent
=
parent
.
aq_self
parent
=
aq_parent
(
parent
)
else
:
return
r
def
_check_context
(
self
,
object
):
...
...
@@ -160,19 +163,15 @@ class BasicUser(Implicit):
# to prevent "stealing" access through acquisition tricks.
# Return true if in context, false if not or if context
# cannot be determined (object is not wrapped).
parent
=
getattr
(
self
,
'
aq_parent
'
,
None
)
context
=
getattr
(
parent
,
'
aq_parent
'
,
None
)
parent
=
getattr
(
self
,
'
__parent__
'
,
None
)
context
=
getattr
(
parent
,
'
__parent__
'
,
None
)
if
context
is
not
None
:
if
object
is
None
:
return
1
if
not
hasattr
(
object
,
'aq_inContextOf'
):
if
hasattr
(
object
,
'im_self'
):
# This is a method. Grab its self.
object
=
object
.
im_self
if
not
hasattr
(
object
,
'aq_inContextOf'
):
# Object is not wrapped, so return false.
return
0
return
object
.
aq_inContextOf
(
context
,
1
)
if
hasattr
(
object
,
'im_self'
):
# This is a method. Grab its self.
object
=
object
.
im_self
return
aq_inContextOf
(
object
,
context
,
1
)
# This is lame, but required to keep existing behavior.
return
1
...
...
@@ -230,7 +229,7 @@ class BasicUser(Implicit):
return
1
return
0
inner
=
getattr
(
inner_obj
,
'aq_inner'
,
inner_obj
)
parent
=
getattr
(
inner
,
'
aq_parent
'
,
None
)
parent
=
getattr
(
inner
,
'
__parent__
'
,
None
)
if
parent
is
not
None
:
inner_obj
=
parent
continue
...
...
@@ -751,11 +750,11 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
request
.
RESPONSE
.
notFoundError
(
'no default view (root default view'
' was probably deleted)'
)
n
=
request
.
steps
[
-
1
]
# default to accessed and container as v.
aq_parent
# default to accessed and container as v.
__parent__
a
=
c
=
request
[
'PARENTS'
][
0
]
# try to find actual container
inner
=
getattr
(
v
,
'aq_inner'
,
v
)
innerparent
=
getattr
(
inner
,
'
aq_parent
'
,
None
)
innerparent
=
getattr
(
inner
,
'
__parent__
'
,
None
)
if
innerparent
is
not
None
:
# this is not a method, we needn't treat it specially
c
=
innerparent
...
...
@@ -763,8 +762,8 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
# this is a method, we need to treat it specially
c
=
v
.
im_self
c
=
getattr
(
v
,
'aq_inner'
,
v
)
request_container
=
getattr
(
request
[
'PARENTS'
][
-
1
],
'
aq_parent
'
,
[])
# if pub's
aq_parent
or container is the request container, it
request_container
=
getattr
(
request
[
'PARENTS'
][
-
1
],
'
__parent__
'
,
[])
# if pub's
__parent__
or container is the request container, it
# means pub was accessed from the root
if
a
is
request_container
:
a
=
request
[
'PARENTS'
][
-
1
]
...
...
@@ -775,7 +774,7 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
def
_isTop
(
self
):
try
:
return
self
.
aq_parent
.
aq_base
.
isTopLevelPrincipiaApplicationObject
return
aq_base
(
aq_parent
(
self
))
.
isTopLevelPrincipiaApplicationObject
except
:
return
0
...
...
@@ -990,8 +989,8 @@ class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
def
manage_afterAdd
(
self
,
item
,
container
):
if
item
is
self
:
if
hasattr
(
self
,
'aq_base'
):
self
=
self
.
aq_base
container
.
__allow_groups__
=
self
self
=
aq_base
(
self
)
container
.
__allow_groups__
=
self
def
__creatable_by_emergency_user__
(
self
):
return
1
...
...
lib/python/AccessControl/cAccessControl.c
View file @
17b5a358
...
...
@@ -1878,13 +1878,11 @@ c_rolesForPermissionOn(PyObject *perm, PyObject *object,
/*
object =
getattr(object, 'aq_inner', None
)
object =
aq_inner(object
)
if object is None:
break
object =
object.aq_parent
object =
aq_parent(object)
*/
if
(
!
aq_isWrapper
(
object
))
break
;
{
PyObject
*
tobj
=
aq_inner
(
object
);
if
(
tobj
==
NULL
)
...
...
@@ -1895,8 +1893,6 @@ c_rolesForPermissionOn(PyObject *perm, PyObject *object,
if
(
object
==
Py_None
)
break
;
if
(
!
aq_isWrapper
(
object
))
break
;
tobj
=
aq_parent
(
object
);
if
(
tobj
==
NULL
)
goto
end
;
...
...
lib/python/Acquisition/_Acquisition.c
View file @
17b5a358
...
...
@@ -38,7 +38,8 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*
py__long__
,
*
py__float__
,
*
py__oct__
,
*
py__hex__
,
*
py__getitem__
,
*
py__setitem__
,
*
py__delitem__
,
*
py__getslice__
,
*
py__setslice__
,
*
py__delslice__
,
*
py__contains__
,
*
py__len__
,
*
py__of__
,
*
py__call__
,
*
py__repr__
,
*
py__str__
,
*
py__cmp__
;
*
py__len__
,
*
py__of__
,
*
py__call__
,
*
py__repr__
,
*
py__str__
,
*
py__cmp__
,
*
py__parent__
;
static
PyObject
*
Acquired
=
0
;
...
...
@@ -82,7 +83,7 @@ init_py_names(void)
INIT_PY_NAME
(
__repr__
);
INIT_PY_NAME
(
__str__
);
INIT_PY_NAME
(
__cmp__
);
INIT_PY_NAME
(
__parent__
);
#undef INIT_PY_NAME
}
...
...
@@ -414,23 +415,49 @@ static PyObject *
Wrapper_findattr
(
Wrapper
*
self
,
PyObject
*
oname
,
PyObject
*
filter
,
PyObject
*
extra
,
PyObject
*
orig
,
int
sob
,
int
sco
,
int
explicit
,
int
containment
)
/*
Parameters:
sob
Search self->obj for the 'oname' attribute
sco
Search self->container for the 'oname' attribute
explicit
Explicitly acquire 'oname' attribute from container (assumed with
implicit acquisition wrapper)
containment
Use the innermost wrapper ("aq_inner") for looking up the 'oname'
attribute.
*/
{
PyObject
*
r
,
*
v
,
*
tb
;
char
*
name
=
""
;
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
(
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
)
if
((
r
=
Wrapper_special
(
self
,
name
+
3
,
oname
)))
{
if
(
filter
)
switch
(
apply_filter
(
filter
,
OBJECT
(
self
),
oname
,
r
,
extra
,
orig
))
{
case
-
1
:
return
NULL
;
case
1
:
return
r
;
}
else
return
r
;
}
else
PyErr_Clear
();
if
((
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
)
||
(
strcmp
(
name
,
"__parent__"
)
==
0
))
{
/* __parent__ is an alias to aq_parent */
if
(
strcmp
(
name
,
"__parent__"
)
==
0
)
name
=
"parent"
;
else
name
=
name
+
3
;
if
((
r
=
Wrapper_special
(
self
,
name
,
oname
)))
{
if
(
filter
)
switch
(
apply_filter
(
filter
,
OBJECT
(
self
),
oname
,
r
,
extra
,
orig
))
{
case
-
1
:
return
NULL
;
case
1
:
return
r
;
}
else
return
r
;
}
else
PyErr_Clear
();
}
else
if
(
*
name
==
'_'
&&
name
[
1
]
==
'_'
&&
(
strcmp
(
name
+
2
,
"reduce__"
)
==
0
||
strcmp
(
name
+
2
,
"reduce_ex__"
)
==
0
||
...
...
@@ -477,6 +504,7 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
Py_XDECREF
(
r
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
r
=
NULL
;
}
/* normal attribute lookup */
else
if
((
r
=
PyObject_GetAttr
(
self
->
obj
,
oname
)))
{
if
(
r
==
Acquired
)
...
...
@@ -511,6 +539,7 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
PyErr_Clear
();
}
/* Lookup has failed, acquire it from parent. */
if
(
sco
&&
(
*
name
!=
'_'
||
explicit
))
return
Wrapper_acquire
(
self
,
oname
,
filter
,
extra
,
orig
,
explicit
,
containment
);
...
...
@@ -524,23 +553,34 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject
*
filter
,
PyObject
*
extra
,
PyObject
*
orig
,
int
explicit
,
int
containment
)
{
PyObject
*
r
;
PyObject
*
r
,
*
v
,
*
tb
;
int
sob
=
1
,
sco
=
1
;
if
(
self
->
container
)
{
/* If the container has an acquisition wrapper itself, we'll use
Wrapper_findattr to progress further. */
if
(
isWrapper
(
self
->
container
))
{
if
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
{
/* Try to optimize search by recognizing repeated obs in path */
/* Try to optimize search by recognizing repeated
objects in path. */
if
(
WRAPPER
(
self
->
obj
)
->
container
==
WRAPPER
(
self
->
container
)
->
container
)
sco
=
0
;
else
if
(
WRAPPER
(
self
->
obj
)
->
container
==
WRAPPER
(
self
->
container
)
->
obj
)
sob
=
0
;
}
}
/* Don't search the container when the container of the
container is the same object as 'self'. */
if
(
WRAPPER
(
self
->
container
)
->
container
==
WRAPPER
(
self
)
->
obj
)
{
sco
=
0
;
containment
=
1
;
}
r
=
Wrapper_findattr
((
Wrapper
*
)
self
->
container
,
oname
,
filter
,
extra
,
orig
,
sob
,
sco
,
explicit
,
...
...
@@ -549,8 +589,46 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
if
(
r
&&
has__of__
(
r
))
ASSIGN
(
r
,
__of__
(
r
,
OBJECT
(
self
)));
return
r
;
}
/* If the container has a __parent__ pointer, we create an
acquisition wrapper for it accordingly. Then we can proceed
with Wrapper_findattr, just as if the container had an
acquisition wrapper in the first place (see above). */
else
if
((
r
=
PyObject_GetAttr
(
self
->
container
,
py__parent__
)))
{
ASSIGN
(
self
->
container
,
newWrapper
(
self
->
container
,
r
,
(
PyTypeObject
*
)
&
Wrappertype
));
/* Don't search the container when the parent of the parent
is the same object as 'self' */
if
(
WRAPPER
(
r
)
->
obj
==
WRAPPER
(
self
)
->
obj
)
sco
=
0
;
Py_DECREF
(
r
);
/* don't need __parent__ anymore */
r
=
Wrapper_findattr
((
Wrapper
*
)
self
->
container
,
oname
,
filter
,
extra
,
orig
,
sob
,
sco
,
explicit
,
containment
);
/* There's no need to DECREF the wrapper here because it's
not stored in self->container, thus 'self' owns its
reference now */
return
r
;
}
/* The container is the end of the acquisition chain; if we
can't look up the attribute here, we can't look it up at
all. */
else
{
/* We need to clean up the AttributeError from the previous
getattr (because it has clearly failed). */
PyErr_Fetch
(
&
r
,
&
v
,
&
tb
);
if
(
r
&&
(
r
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
r
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
r
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
r
=
NULL
;
if
((
r
=
PyObject_GetAttr
(
self
->
container
,
oname
)))
{
if
(
r
==
Acquired
)
{
Py_DECREF
(
r
);
...
...
@@ -618,8 +696,8 @@ Wrapper_setattro(Wrapper *self, PyObject *oname, PyObject *v)
/* Allow assignment to parent, to change context. */
if
(
PyString_Check
(
oname
))
name
=
PyString_AS_STRING
(
oname
);
if
(
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
&&
strcmp
(
name
+
3
,
"parent"
)
==
0
)
if
(
(
*
name
==
'a'
&&
name
[
1
]
==
'q'
&&
name
[
2
]
==
'_'
&&
strcmp
(
name
+
3
,
"parent"
)
==
0
)
||
(
strcmp
(
name
,
"__parent__"
)
==
0
)
)
{
Py_XINCREF
(
v
);
ASSIGN
(
self
->
container
,
v
);
...
...
@@ -1112,57 +1190,18 @@ Wrapper_acquire_method(Wrapper *self, PyObject *args, PyObject *kw)
# endif
}
/* forward declaration so that we can use it in Wrapper_inContextOf */
static
PyObject
*
capi_aq_inContextOf
(
PyObject
*
self
,
PyObject
*
o
,
int
inner
);
static
PyObject
*
Wrapper_inContextOf
(
Wrapper
*
self
,
PyObject
*
args
)
{
PyObject
*
subob
,
*
o
,
*
c
;
int
inner
=
1
;
PyObject
*
o
;
int
inner
=
1
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|i"
,
&
o
,
&
inner
))
return
NULL
;
if
(
inner
)
{
/* subob = self */
subob
=
OBJECT
(
self
);
/* o = aq_base(o) */
while
(
isWrapper
(
o
)
&&
WRAPPER
(
o
)
->
obj
)
o
=
WRAPPER
(
o
)
->
obj
;
/* while 1: */
while
(
1
)
{
/* if aq_base(subob) is o: return 1 */
c
=
subob
;
while
(
isWrapper
(
c
)
&&
WRAPPER
(
c
)
->
obj
)
c
=
WRAPPER
(
c
)
->
obj
;
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
/* self = aq_inner(subob) */
/* if self is None: break */
if
(
isWrapper
(
subob
))
{
self
=
WRAPPER
(
subob
);
while
(
self
->
obj
&&
isWrapper
(
self
->
obj
))
self
=
WRAPPER
(
self
->
obj
);
}
else
break
;
/* subob = aq_parent(self) */
/* if subob is None: break */
if
(
self
->
container
)
subob
=
self
->
container
;
else
break
;
}
}
else
{
/* Follow wrappers instead. */
c
=
OBJECT
(
self
);
while
(
1
)
{
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
if
(
c
&&
isWrapper
(
c
))
c
=
WRAPPER
(
c
)
->
container
;
else
break
;
}
}
return
PyInt_FromLong
(
0
);
return
capi_aq_inContextOf
((
PyObject
*
)
self
,
o
,
inner
);
}
PyObject
*
...
...
@@ -1332,8 +1371,7 @@ static PyObject *
capi_aq_acquire
(
PyObject
*
self
,
PyObject
*
name
,
PyObject
*
filter
,
PyObject
*
extra
,
int
explicit
,
PyObject
*
defalt
,
int
containment
)
{
PyObject
*
result
;
PyObject
*
result
,
*
v
,
*
tb
;
if
(
filter
==
Py_None
)
filter
=
0
;
...
...
@@ -1343,22 +1381,46 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
explicit
||
WRAPPER
(
self
)
->
ob_type
==
(
PyTypeObject
*
)
&
Wrappertype
,
explicit
,
containment
);
/* Not wrapped and no filter, so just getattr */
if
(
!
filter
)
return
PyObject_GetAttr
(
self
,
name
);
explicit
,
containment
);
/* Not wrapped; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
self
=
newWrapper
(
self
,
result
,
(
PyTypeObject
*
)
&
Wrappertype
);
Py_DECREF
(
result
);
/* don't need __parent__ anymore */
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
/* Get rid of temporary wrapper */
Py_DECREF
(
self
);
return
result
;
}
/* No wrapper and no __parent__, so just getattr. */
else
{
/* Clean up the AttributeError from the previous getattr
(because it has clearly failed). */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
/* Crap, we've got to construct a wrapper so we can use Wrapper_findattr */
UNLESS
(
self
=
newWrapper
(
self
,
Py_None
,
(
PyTypeObject
*
)
&
Wrappertype
))
return
NULL
;
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
if
(
!
filter
)
return
PyObject_GetAttr
(
self
,
name
);
/* get rid of temp wrapper */
Py_DECREF
(
self
);
/* Crap, we've got to construct a wrapper so we can use
Wrapper_findattr */
UNLESS
(
self
=
newWrapper
(
self
,
Py_None
,
(
PyTypeObject
*
)
&
Wrappertype
))
return
NULL
;
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
filter
,
extra
,
OBJECT
(
self
),
1
,
1
,
explicit
,
containment
);
return
result
;
/* Get rid of temporary wrapper */
Py_DECREF
(
self
);
return
result
;
}
}
static
PyObject
*
...
...
@@ -1384,13 +1446,35 @@ module_aq_acquire(PyObject *ignored, PyObject *args, PyObject *kw)
static
PyObject
*
capi_aq_get
(
PyObject
*
self
,
PyObject
*
name
,
PyObject
*
defalt
,
int
containment
)
{
PyObject
*
result
=
NULL
;
PyObject
*
result
=
NULL
,
*
v
,
*
tb
;
/* We got a wrapped object, so business as usual */
if
(
isWrapper
(
self
))
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
0
,
0
,
OBJECT
(
self
),
1
,
1
,
1
,
containment
);
containment
);
/* Not wrapped; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
self
=
newWrapper
(
self
,
result
,
(
PyTypeObject
*
)
&
Wrappertype
);
Py_DECREF
(
result
);
/* don't need __parent__ anymore */
result
=
Wrapper_findattr
(
WRAPPER
(
self
),
name
,
0
,
0
,
OBJECT
(
self
),
1
,
1
,
1
,
containment
);
Py_DECREF
(
self
);
/* Get rid of temporary wrapper. */
}
else
result
=
PyObject_GetAttr
(
self
,
name
);
{
/* Clean up the AttributeError from the previous getattr
(because it has clearly failed). */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
result
=
PyObject_GetAttr
(
self
,
name
);
}
if
(
!
result
&&
defalt
)
{
...
...
@@ -1453,13 +1537,34 @@ module_aq_base(PyObject *ignored, PyObject *args)
static
PyObject
*
capi_aq_parent
(
PyObject
*
self
)
{
PyObject
*
result
=
Py_None
;
PyObject
*
result
,
*
v
,
*
tb
;
if
(
isWrapper
(
self
)
&&
WRAPPER
(
self
)
->
container
)
result
=
WRAPPER
(
self
)
->
container
;
{
result
=
WRAPPER
(
self
)
->
container
;
Py_INCREF
(
result
);
return
result
;
}
else
if
((
result
=
PyObject_GetAttr
(
self
,
py__parent__
)))
/* We already own the reference to result (PyObject_GetAttr gives
it to us), no need to INCREF here */
return
result
;
else
{
/* We need to clean up the AttributeError from the previous
getattr (because it has clearly failed) */
PyErr_Fetch
(
&
result
,
&
v
,
&
tb
);
if
(
result
&&
(
result
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
result
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
result
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
Py_INCREF
(
result
);
return
result
;
result
=
Py_None
;
Py_INCREF
(
result
);
return
result
;
}
}
static
PyObject
*
...
...
@@ -1535,7 +1640,7 @@ module_aq_inner(PyObject *ignored, PyObject *args)
static
PyObject
*
capi_aq_chain
(
PyObject
*
self
,
int
containment
)
{
PyObject
*
result
;
PyObject
*
result
,
*
v
,
*
tb
;
UNLESS
(
result
=
PyList_New
(
0
))
return
NULL
;
...
...
@@ -1558,8 +1663,27 @@ capi_aq_chain(PyObject *self, int containment)
}
}
else
if
(
PyList_Append
(
result
,
self
)
<
0
)
goto
err
;
{
if
(
PyList_Append
(
result
,
self
)
<
0
)
goto
err
;
if
((
self
=
PyObject_GetAttr
(
self
,
py__parent__
)))
{
Py_DECREF
(
self
);
/* We don't need our own reference. */
if
(
self
!=
Py_None
)
continue
;
}
else
{
PyErr_Fetch
(
&
self
,
&
v
,
&
tb
);
if
(
self
&&
(
self
!=
PyExc_AttributeError
))
{
PyErr_Restore
(
self
,
v
,
tb
);
return
NULL
;
}
Py_XDECREF
(
self
);
Py_XDECREF
(
v
);
Py_XDECREF
(
tb
);
}
}
break
;
}
...
...
@@ -1582,6 +1706,53 @@ module_aq_chain(PyObject *ignored, PyObject *args)
return
capi_aq_chain
(
self
,
containment
);
}
static
PyObject
*
capi_aq_inContextOf
(
PyObject
*
self
,
PyObject
*
o
,
int
inner
)
{
PyObject
*
next
,
*
c
;
/* next = self
o = aq_base(o) */
next
=
self
;
while
(
isWrapper
(
o
)
&&
WRAPPER
(
o
)
->
obj
)
o
=
WRAPPER
(
o
)
->
obj
;
while
(
1
)
{
/* if aq_base(next) is o: return 1 */
c
=
next
;
while
(
isWrapper
(
c
)
&&
WRAPPER
(
c
)
->
obj
)
c
=
WRAPPER
(
c
)
->
obj
;
if
(
c
==
o
)
return
PyInt_FromLong
(
1
);
if
(
inner
)
{
self
=
capi_aq_inner
(
next
);
Py_DECREF
(
self
);
/* We're not holding on to the inner wrapper */
if
(
self
==
Py_None
)
break
;
}
else
self
=
next
;
next
=
capi_aq_parent
(
self
);
Py_DECREF
(
next
);
/* We're not holding on to the parent */
if
(
next
==
Py_None
)
break
;
}
return
PyInt_FromLong
(
0
);
}
static
PyObject
*
module_aq_inContextOf
(
PyObject
*
ignored
,
PyObject
*
args
)
{
PyObject
*
self
,
*
o
;
int
inner
=
1
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"OO|i"
,
&
self
,
&
o
,
&
inner
))
return
NULL
;
return
capi_aq_inContextOf
(
self
,
o
,
inner
);
}
static
struct
PyMethodDef
methods
[]
=
{
{
"aq_acquire"
,
(
PyCFunction
)
module_aq_acquire
,
METH_VARARGS
|
METH_KEYWORDS
,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
...
...
@@ -1599,10 +1770,13 @@ static struct PyMethodDef methods[] = {
"aq_self(ob) -- Get the object with the outermost wrapper removed"
},
{
"aq_inner"
,
(
PyCFunction
)
module_aq_inner
,
METH_VARARGS
,
"aq_inner(ob) -- "
"Get the object with all
l
but the innermost wrapper removed"
},
"Get the object with all but the innermost wrapper removed"
},
{
"aq_chain"
,
(
PyCFunction
)
module_aq_chain
,
METH_VARARGS
,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"
},
{
"aq_inContextOf"
,
(
PyCFunction
)
module_aq_inContextOf
,
METH_VARARGS
,
"aq_inContextOf(base, ob [, inner]) -- "
"Determine whether the object is in the acquisition context of base."
},
{
NULL
,
NULL
}
};
...
...
lib/python/Acquisition/tests.py
View file @
17b5a358
...
...
@@ -357,6 +357,11 @@ def test_unwrapped():
...
AttributeError: aq_parent
>>> c.__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
>>> Acquisition.aq_acquire(c, 'id')
'unwrapped'
>>> Acquisition.aq_acquire(c, 'x')
...
...
@@ -452,6 +457,13 @@ def test_simple():
>>> a.b.c.aq_inContextOf(a.b.c)
1
>>> Acquisition.aq_inContextOf(a.b.c, a)
1
>>> Acquisition.aq_inContextOf(a.b.c, a.b)
1
>>> Acquisition.aq_inContextOf(a.b.c, a.b.c)
1
>>> a.b.c.aq_acquire('y')
42
...
...
@@ -533,6 +545,13 @@ def test_simple():
>>> show(Acquisition.aq_self(a.b.c))
c
A wrapper's __parent__ attribute (which is equivalent to its
aq_parent attribute) points to the Acquisition parent.
>>> a.b.c.__parent__ == a.b.c.aq_parent
True
>>> a.b.c.__parent__ == a.b
True
"""
def
test__of__exception
():
...
...
@@ -1201,7 +1220,7 @@ def test_mixed_explicit_and_explicit():
"""
def
old_tests
():
def
test_aq_inContextOf
():
"""
>>> from ExtensionClass import Base
>>> import Acquisition
...
...
@@ -1213,6 +1232,9 @@ def old_tests():
... def hi(self):
... print "%s()" % self.__class__.__name__, self.color
>>> class Location(object):
... __parent__ = None
>>> b=B()
>>> b.a=A()
>>> b.a.hi()
...
...
@@ -1242,25 +1264,52 @@ def old_tests():
>>> b.c == c
1
>>> l = Location()
>>> l.__parent__ = b.c
>>> def checkContext(self, o):
... # Python equivalent to aq_inContextOf
... from Acquisition import aq_base, aq_parent, aq_inner
...
subob
= self
...
next
= self
... o = aq_base(o)
... while 1:
... if aq_base(subob) is o: return 1
... self = aq_inner(subob)
... if self is None: break
... subob = aq_parent(self)
... if subob is None: break
... if aq_base(next) is o:
... return 1
... self = aq_inner(next)
... if self is None:
... break
... next = aq_parent(self)
... if next is None:
... break
... return 0
>>> checkContext(b.c, b)
1
>>> not checkContext(b.c, b.a)
1
>>> checkContext(l, b)
1
>>> checkContext(l, b.c)
1
>>> not checkContext(l, b.a)
1
Acquisition.aq_inContextOf works the same way:
>>> Acquisition.aq_inContextOf(b.c, b)
1
>>> Acquisition.aq_inContextOf(b.c, b.a)
0
>>> Acquisition.aq_inContextOf(l, b)
1
>>> Acquisition.aq_inContextOf(l, b.c)
1
>>> Acquisition.aq_inContextOf(l, b.a)
0
>>> b.a.aq_inContextOf(b)
1
>>> b.c.aq_inContextOf(b)
...
...
@@ -1271,12 +1320,12 @@ def old_tests():
1
>>> b.c.d.aq_inContextOf(b.c)
1
>>>
not
b.c.aq_inContextOf(foo)
1
>>>
not
b.c.aq_inContextOf(b.a)
1
>>>
not
b.a.aq_inContextOf('somestring')
1
>>> b.c.aq_inContextOf(foo)
0
>>> b.c.aq_inContextOf(b.a)
0
>>> b.a.aq_inContextOf('somestring')
0
"""
def
test_AqAlg
():
...
...
@@ -1389,7 +1438,7 @@ def test_creating_wrappers_directly():
...
TypeError: __init__() takes exactly 2 arguments (1 given)
We can reassign aq_parent
We can reassign aq_parent
/ __parent__ on a wrapper:
>>> x = B()
>>> x.color = 'green'
...
...
@@ -1397,6 +1446,20 @@ def test_creating_wrappers_directly():
>>> w.color
'green'
>>> y = B()
>>> y.color = 'blue'
>>> w.__parent__ = y
>>> w.color
'blue'
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(w).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
>>> w = ImplicitAcquisitionWrapper()
Traceback (most recent call last):
...
...
...
@@ -1664,6 +1727,434 @@ def test_proxying():
"""
class
Location
(
object
):
__parent__
=
None
class
ECLocation
(
ExtensionClass
.
Base
):
__parent__
=
None
def
test___parent__no_wrappers
():
"""
Acquisition also works with objects that aren't wrappers, as long
as they have __parent__ pointers. Let's take a hierarchy like
z --isParent--> y --isParent--> x:
>>> x = Location()
>>> y = Location()
>>> z = Location()
>>> x.__parent__ = y
>>> y.__parent__ = z
and some attributes that we want to acquire:
>>> x.hello = 'world'
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
``aq_acquire`` works as we know it from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
"""
def
test_implicit_wrapper_as___parent__
():
"""
Let's do the same test again, only now not all objects are of the
same kind and link to each other via __parent__ pointers. The
root is a stupid ExtensionClass object:
>>> class Root(ExtensionClass.Base):
... bar = 3.145
>>> z = Root()
The intermediate parent is an object that supports implicit
acquisition. We bind it to the root via the __of__ protocol:
>>> class Impl(Acquisition.Implicit):
... foo = 42
>>> y = Impl().__of__(z)
The child object is again a simple object with a simple __parent__
pointer:
>>> x = Location()
>>> x.hello = 'world'
>>> x.__parent__ = y
``aq_acquire`` works as expected from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
Note that also the (implicit) acquisition wrapper has a __parent__
pointer, which is automatically computed from the acquisition
container (it's identical to aq_parent):
>>> y.__parent__ is z
True
Just as much as you can assign to aq_parent, you can also assign
to __parent__ to change the acquisition context of the wrapper:
>>> newroot = Root()
>>> y.__parent__ = newroot
>>> y.__parent__ is z
False
>>> y.__parent__ is newroot
True
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(y).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
"""
def
test_explicit_wrapper_as___parent__
():
"""
Let's do this test yet another time, with an explicit wrapper:
>>> class Root(ExtensionClass.Base):
... bar = 3.145
>>> z = Root()
The intermediate parent is an object that supports implicit
acquisition. We bind it to the root via the __of__ protocol:
>>> class Expl(Acquisition.Explicit):
... foo = 42
>>> y = Expl().__of__(z)
The child object is again a simple object with a simple __parent__
pointer:
>>> x = Location()
>>> x.hello = 'world'
>>> x.__parent__ = y
``aq_acquire`` works as expected from implicit/acquisition
wrappers:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) is y
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
Note that also the (explicit) acquisition wrapper has a __parent__
pointer, which is automatically computed from the acquisition
container (it's identical to aq_parent):
>>> y.__parent__ is z
True
Just as much as you can assign to aq_parent, you can also assign
to __parent__ to change the acquisition context of the wrapper:
>>> newroot = Root()
>>> y.__parent__ = newroot
>>> y.__parent__ is z
False
>>> y.__parent__ is newroot
True
Note that messing with the wrapper won't in any way affect the
wrapped object:
>>> Acquisition.aq_base(y).__parent__
Traceback (most recent call last):
...
AttributeError: __parent__
"""
def
test_implicit_wrapper_has_nonwrapper_as_aq_parent
():
"""Let's do this the other way around: The root and the
intermediate parent is an object that doesn't support acquisition,
>>> y = ECLocation()
>>> z = Location()
>>> y.__parent__ = z
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
only the outmost object does:
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> x = Impl().__of__(y)
Again, acquiring objects works as usual:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) == y
True
>>> x.aq_parent == y
True
>>> x.aq_parent.aq_parent == z
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
>>> x.aq_chain == [x, y, z]
True
Because the outmost object, ``x``, is wrapped in an implicit
acquisition wrapper, we can also use direct attribute access:
>>> x.hello
'world'
>>> x.foo
42
>>> x.bar
3.145
"""
def
test_explicit_wrapper_has_nonwrapper_as_aq_parent
():
"""Let's do this the other way around: The root and the
intermediate parent is an object that doesn't support acquisition,
>>> y = ECLocation()
>>> z = Location()
>>> y.__parent__ = z
>>> y.foo = 42
>>> z.foo = 43 # this should not be found
>>> z.bar = 3.145
only the outmost object does:
>>> class Expl(Acquisition.Explicit):
... hello = 'world'
>>> x = Expl().__of__(y)
Again, acquiring objects works as usual:
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'foo')
42
>>> Acquisition.aq_acquire(x, 'bar')
3.145
as does ``aq_get``:
>>> Acquisition.aq_get(x, 'hello')
'world'
>>> Acquisition.aq_get(x, 'foo')
42
>>> Acquisition.aq_get(x, 'bar')
3.145
and ``aq_parent``:
>>> Acquisition.aq_parent(x) == y
True
>>> x.aq_parent == y
True
>>> x.aq_parent.aq_parent == z
True
>>> Acquisition.aq_parent(y) is z
True
as well as ``aq_chain``:
>>> Acquisition.aq_chain(x) == [x, y, z]
True
>>> x.aq_chain == [x, y, z]
True
"""
def
test___parent__aq_parent_circles
():
"""
As a general safety belt, Acquisition won't follow a mixture of
circular __parent__ pointers and aq_parent wrappers. These can
occurr when code that uses implicit acquisition wrappers meets
code that uses __parent__ pointers.
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> class Impl2(Acquisition.Implicit):
... hello = 'world2'
... only = 'here'
>>> x = Impl()
>>> y = Impl2().__of__(x)
>>> x.__parent__ = y
>>> x.__parent__.aq_base is y.aq_base
True
>>> x.__parent__.__parent__ is x
True
>>> x.hello
'world'
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> x.only
Traceback (most recent call last):
...
AttributeError: only
>>> Acquisition.aq_acquire(x, 'only')
'here'
>>> Acquisition.aq_acquire(x, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> Acquisition.aq_acquire(y, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> x.non_existant_attr
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> y.non_existant_attr
Traceback (most recent call last):
...
AttributeError: non_existant_attr
"""
def
test___parent__parent__circles
():
"""
Acquisition won't follow circular __parent__ references:
>>> class Impl(Acquisition.Implicit):
... hello = 'world'
>>> class Impl2(Acquisition.Implicit):
... hello = 'world2'
... only = 'here'
>>> x = Impl()
>>> y = Impl2()
>>> x.__parent__ = y
>>> y.__parent__ = x
>>> x.__parent__.__parent__ is x
True
>>> Acquisition.aq_acquire(x, 'hello')
'world'
>>> Acquisition.aq_acquire(x, 'only')
'here'
>>> Acquisition.aq_acquire(x, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
>>> Acquisition.aq_acquire(y, 'non_existant_attr')
Traceback (most recent call last):
...
AttributeError: non_existant_attr
"""
import
unittest
from
zope.testing.doctest
import
DocTestSuite
,
DocFileSuite
...
...
lib/python/App/FactoryDispatcher.py
View file @
17b5a358
...
...
@@ -66,7 +66,7 @@ class FactoryDispatcher(Acquisition.Implicit):
_owner
=
UnownableOwner
def
__init__
(
self
,
product
,
dest
,
REQUEST
=
None
):
if
hasattr
(
product
,
'aq_base'
):
product
=
product
.
aq_base
product
=
Acquisition
.
aq_base
(
product
)
self
.
_product
=
product
self
.
_d
=
dest
if
REQUEST
is
not
None
:
...
...
@@ -100,7 +100,7 @@ class FactoryDispatcher(Acquisition.Implicit):
m
=
d
[
name
]
w
=
getattr
(
m
,
'_permissionMapper'
,
None
)
if
w
is
not
None
:
m
=
aqwrap
(
m
,
getattr
(
w
,
'aq_base'
,
w
),
self
)
m
=
aqwrap
(
m
,
Acquisition
.
aq_base
(
w
),
self
)
return
m
...
...
lib/python/OFS/FindSupport.py
View file @
17b5a358
...
...
@@ -22,6 +22,7 @@ from AccessControl import ClassSecurityInfo
from
AccessControl.DTML
import
RestrictedDTML
from
AccessControl.Permission
import
name_trans
from
AccessControl.Permissions
import
view_management_screens
from
Acquisition
import
aq_base
from
DateTime
import
DateTime
from
DocumentTemplate.DT_Util
import
Eval
from
DocumentTemplate.DT_Util
import
InstanceDict
,
TemplateDict
...
...
@@ -92,9 +93,7 @@ class FindSupport(ExtensionClass.Base):
md
=
td
()
obj_expr
=
(
Eval
(
obj_expr
),
md
,
md
.
_push
,
md
.
_pop
)
base
=
obj
if
hasattr
(
obj
,
'aq_base'
):
base
=
obj
.
aq_base
base
=
aq_base
(
obj
)
if
hasattr
(
base
,
'objectItems'
):
try
:
items
=
obj
.
objectItems
()
...
...
@@ -118,9 +117,7 @@ class FindSupport(ExtensionClass.Base):
if
hasattr
(
ob
,
'_p_changed'
)
and
(
ob
.
_p_changed
==
None
):
dflag
=
1
if
hasattr
(
ob
,
'aq_base'
):
bs
=
ob
.
aq_base
else
:
bs
=
ob
bs
=
aq_base
(
ob
)
if
(
(
not
obj_ids
or
absattr
(
bs
.
getId
())
in
obj_ids
)
and
...
...
@@ -200,9 +197,7 @@ class FindSupport(ExtensionClass.Base):
md
=
td
()
obj_expr
=
(
Eval
(
obj_expr
),
md
,
md
.
_push
,
md
.
_pop
)
base
=
obj
if
hasattr
(
obj
,
'aq_base'
):
base
=
obj
.
aq_base
base
=
aq_base
(
obj
)
if
not
hasattr
(
base
,
'objectItems'
):
return
result
...
...
@@ -221,10 +216,7 @@ class FindSupport(ExtensionClass.Base):
if
hasattr
(
ob
,
'_p_changed'
)
and
(
ob
.
_p_changed
==
None
):
dflag
=
1
if
hasattr
(
ob
,
'aq_base'
):
bs
=
ob
.
aq_base
else
:
bs
=
ob
bs
=
aq_base
(
ob
)
if
(
(
not
obj_ids
or
absattr
(
bs
.
getId
())
in
obj_ids
)
and
...
...
lib/python/OFS/PropertySheets.py
View file @
17b5a358
...
...
@@ -20,13 +20,14 @@ from webdav.WriteLockInterface import WriteLockInterface
from
ZPublisher.Converters
import
type_converters
from
Globals
import
InitializeClass
from
Globals
import
DTMLFile
,
MessageDialog
from
Acquisition
import
aq_base
from
Acquisition
import
aq_parent
from
Acquisition
import
Implicit
,
Explicit
from
App.Common
import
rfc1123_date
,
iso8601_date
from
webdav.common
import
urlbase
from
ExtensionClass
import
Base
from
Globals
import
Persistent
from
Traversable
import
Traversable
from
Acquisition
import
aq_base
from
AccessControl
import
ClassSecurityInfo
from
AccessControl.Permissions
import
access_contents_information
from
AccessControl.Permissions
import
manage_properties
...
...
@@ -71,7 +72,7 @@ class View(App.Management.Tabs, Base):
pre
=
pre
+
'/'
r
=
[]
for
d
in
self
.
aq_parent
.
aq_parent
.
manage_options
:
for
d
in
aq_parent
(
aq_parent
(
self
))
.
manage_options
:
path
=
d
[
'action'
]
option
=
{
'label'
:
d
[
'label'
],
'action'
:
pre
+
path
,
...
...
@@ -92,7 +93,7 @@ class View(App.Management.Tabs, Base):
self
,
script
,
path
)
def
meta_type
(
self
):
try
:
return
self
.
aq_parent
.
aq_parent
.
meta_type
try
:
return
aq_parent
(
aq_parent
(
self
))
.
meta_type
except
:
return
''
...
...
@@ -489,7 +490,7 @@ class Virtual:
pass
def
v_self
(
self
):
return
self
.
aq_parent
.
aq_parent
return
aq_parent
(
aq_parent
(
self
))
class
DefaultProperties
(
Virtual
,
PropertySheet
,
View
):
...
...
@@ -635,7 +636,7 @@ class PropertySheets(Traversable, Implicit, App.Management.Tabs):
return
(
self
.
webdav
,)
def
__propsets__
(
self
):
propsets
=
self
.
aq_parent
.
__propsets__
propsets
=
aq_parent
(
self
)
.
__propsets__
__traceback_info__
=
propsets
,
type
(
propsets
)
return
self
.
_get_defaults
()
+
propsets
...
...
@@ -684,17 +685,17 @@ class PropertySheets(Traversable, Implicit, App.Management.Tabs):
security
.
declareProtected
(
manage_properties
,
'addPropertySheet'
)
def
addPropertySheet
(
self
,
propset
):
propsets
=
self
.
aq_parent
.
__propsets__
propsets
=
propsets
+
(
propset
,)
self
.
aq_parent
.
__propsets__
=
propsets
propsets
=
aq_parent
(
self
)
.
__propsets__
propsets
=
propsets
+
(
propset
,)
aq_parent
(
self
).
__propsets__
=
propsets
security
.
declareProtected
(
manage_properties
,
'delPropertySheet'
)
def
delPropertySheet
(
self
,
name
):
result
=
[]
for
propset
in
self
.
aq_parent
.
__propsets__
:
for
propset
in
aq_parent
(
self
)
.
__propsets__
:
if
propset
.
getId
()
!=
name
and
propset
.
xml_namespace
()
!=
name
:
result
.
append
(
propset
)
self
.
aq_parent
.
__propsets__
=
tuple
(
result
)
aq_parent
(
self
)
.
__propsets__
=
tuple
(
result
)
## DM: deletion support
def
isDeletable
(
self
,
name
):
...
...
@@ -743,7 +744,7 @@ class PropertySheets(Traversable, Implicit, App.Management.Tabs):
pre
=
pre
+
'/'
r
=
[]
for
d
in
self
.
aq_parent
.
manage_options
:
for
d
in
aq_parent
(
self
)
.
manage_options
:
r
.
append
({
'label'
:
d
[
'label'
],
'action'
:
pre
+
d
[
'action'
]})
return
r
...
...
lib/python/OFS/SimpleItem.py
View file @
17b5a358
...
...
@@ -205,14 +205,16 @@ class Item(Base, Resource, CopySource, App.Management.Tabs, Traversable,
if
match
is
not
None
:
error_message
=
error_value
if
client
is
None
:
client
=
self
if
not
REQUEST
:
REQUEST
=
self
.
aq_acquire
(
'REQUEST'
)
if
client
is
None
:
client
=
self
if
not
REQUEST
:
REQUEST
=
aq_acquire
(
self
,
'REQUEST'
)
try
:
if
hasattr
(
client
,
'standard_error_message'
):
s
=
getattr
(
client
,
'standard_error_message'
)
else
:
client
=
client
.
aq_parent
client
=
aq_parent
(
client
)
s
=
getattr
(
client
,
'standard_error_message'
)
kwargs
=
{
'error_type'
:
error_type
,
'error_value'
:
error_value
,
...
...
@@ -329,7 +331,7 @@ class Item(Base, Resource, CopySource, App.Management.Tabs, Traversable,
raise
ValueError
(
'FTP List not supported on acquired objects'
)
if
not
hasattr
(
ob
,
'aq_parent'
):
break
ob
=
ob
.
aq_parent
ob
=
aq_parent
(
ob
)
stat
=
marshal
.
loads
(
self
.
manage_FTPstat
(
REQUEST
))
id
=
self
.
getId
()
...
...
lib/python/OFS/Traversable.py
View file @
17b5a358
...
...
@@ -22,7 +22,8 @@ from AccessControl import ClassSecurityInfo
from
AccessControl
import
getSecurityManager
from
AccessControl
import
Unauthorized
from
AccessControl.ZopeGuards
import
guarded_getattr
from
Acquisition
import
Acquired
,
aq_inner
,
aq_parent
,
aq_base
from
Acquisition
import
Acquired
,
aq_inner
,
aq_parent
,
aq_acquire
,
aq_base
from
Acquisition.interfaces
import
IAcquirer
from
zExceptions
import
NotFound
from
ZODB.POSException
import
ConflictError
from
OFS.interfaces
import
ITraversable
...
...
@@ -64,7 +65,7 @@ class Traversable:
spp
=
self
.
getPhysicalPath
()
try
:
toUrl
=
self
.
REQUEST
.
physicalPathToURL
toUrl
=
aq_acquire
(
self
,
'REQUEST'
)
.
physicalPathToURL
except
AttributeError
:
return
path2url
(
spp
[
1
:])
return
toUrl
(
spp
)
...
...
@@ -78,7 +79,7 @@ class Traversable:
"""
spp
=
self
.
getPhysicalPath
()
try
:
toUrl
=
self
.
REQUEST
.
physicalPathToURL
toUrl
=
aq_acquire
(
self
,
'REQUEST'
)
.
physicalPathToURL
except
AttributeError
:
return
path2url
(
spp
)
or
'/'
return
toUrl
(
spp
,
relative
=
1
)
or
'/'
...
...
@@ -93,7 +94,7 @@ class Traversable:
"""
spp
=
self
.
getPhysicalPath
()
try
:
toVirt
=
self
.
REQUEST
.
physicalPathToVirtualPath
toVirt
=
aq_acquire
(
self
,
'REQUEST'
)
.
physicalPathToVirtualPath
except
AttributeError
:
return
path2url
(
spp
[
1
:])
return
path2url
(
toVirt
(
spp
))
...
...
@@ -191,7 +192,9 @@ class Traversable:
ns
,
nm
=
nsParse
(
name
)
try
:
next
=
namespaceLookup
(
ns
,
nm
,
obj
,
self
.
REQUEST
).
__of__
(
obj
)
ns
,
nm
,
obj
,
aq_acquire
(
self
,
'REQUEST'
))
if
IAcquirer
.
providedBy
(
next
):
next
=
next
.
__of__
(
obj
)
if
restricted
and
not
validate
(
obj
,
obj
,
name
,
next
):
raise
Unauthorized
(
name
)
...
...
@@ -256,11 +259,10 @@ class Traversable:
except
(
AttributeError
,
NotFound
,
KeyError
),
e
:
# Try to look for a view
next
=
queryMultiAdapter
((
obj
,
self
.
REQUEST
),
next
=
queryMultiAdapter
((
obj
,
aq_acquire
(
self
,
'REQUEST'
)
),
Interface
,
name
)
if
next
is
not
None
:
next
=
next
.
__of__
(
obj
)
if
restricted
and
not
validate
(
obj
,
obj
,
name
,
next
):
raise
Unauthorized
(
name
)
elif
bobo_traverse
is
not
None
:
...
...
lib/python/OFS/ZDOM.py
View file @
17b5a358
...
...
@@ -16,6 +16,8 @@ DOM implementation in ZOPE : Read-Only methods
All standard Zope objects support DOM to a limited extent.
"""
import
Acquisition
from
Acquisition
import
aq_base
from
Acquisition
import
aq_parent
from
Globals
import
InitializeClass
from
AccessControl
import
ClassSecurityInfo
from
AccessControl.Permissions
import
access_contents_information
...
...
@@ -149,7 +151,7 @@ class Node:
When this is a document this is None"""
node
=
self
if
hasattr
(
node
,
'aq_parent'
):
node
=
self
.
aq_parent
node
=
aq_parent
(
self
)
return
node
.
getOwnerDocument
()
return
node
...
...
@@ -198,7 +200,7 @@ class Document(Acquisition.Explicit, Node):
This is a convenience attribute that allows direct access to
the child node that is the root element of the document.
"""
return
self
.
aq_parent
return
aq_parent
(
self
)
# Node Methods
# ------------
...
...
@@ -219,17 +221,17 @@ class Document(Acquisition.Explicit, Node):
def
getChildNodes
(
self
):
"""Returns a NodeList that contains all children of this node.
If there are no children, this is a empty NodeList"""
return
NodeList
([
self
.
aq_parent
])
return
NodeList
([
aq_parent
(
self
)
])
def
getFirstChild
(
self
):
"""The first child of this node. If there is no such node
this returns None."""
return
self
.
aq_parent
return
aq_parent
(
self
)
def
getLastChild
(
self
):
"""The last child of this node. If there is no such node
this returns None."""
return
self
.
aq_parent
return
aq_parent
(
self
)
def
hasChildNodes
(
self
):
"""Returns true if the node has any children, false
...
...
@@ -324,7 +326,7 @@ class Element(Node):
"""The node immediately preceding this node. If
there is no such node, this returns None."""
if
hasattr
(
self
,
'aq_parent'
):
parent
=
self
.
aq_parent
parent
=
aq_parent
(
self
)
ids
=
list
(
parent
.
objectIds
())
id
=
self
.
id
if
type
(
id
)
is
not
type
(
''
):
id
=
id
()
...
...
@@ -338,7 +340,7 @@ class Element(Node):
"""The node immediately preceding this node. If
there is no such node, this returns None."""
if
hasattr
(
self
,
'aq_parent'
):
parent
=
self
.
aq_parent
parent
=
aq_parent
(
self
)
ids
=
list
(
parent
.
objectIds
())
id
=
self
.
id
if
type
(
id
)
is
not
type
(
''
):
id
=
id
()
...
...
@@ -432,7 +434,7 @@ class ElementWithTitle(Element):
def
getAttribute
(
self
,
name
):
"""Retrieves an attribute value by name."""
if
name
==
'title'
and
hasattr
(
self
.
aq_base
,
'title'
):
if
name
==
'title'
and
hasattr
(
aq_base
(
self
)
,
'title'
):
return
self
.
title
return
''
...
...
lib/python/Products/Five/bbb.py
View file @
17b5a358
...
...
@@ -19,9 +19,31 @@ from zope.interface import Interface, implements
from
zope.component.interfaces
import
ComponentLookupError
from
zope.app.publisher.browser
import
getDefaultViewName
import
zExceptions
import
Products.Five.security
from
Products.Five
import
fivemethod
import
Acquisition
class
AcquisitionBBB
(
object
):
"""Emulate a class implementing Acquisition.interfaces.IAcquirer and
IAcquisitionWrapper.
"""
def
__of__
(
self
,
context
):
# Technically this isn't in line with the way Acquisition's
# __of__ works. With Acquisition, you get a wrapper around
# the original object and only that wrapper's parent is the
# new context.
return
self
aq_self
=
aq_inner
=
aq_base
=
property
(
lambda
self
:
self
)
aq_chain
=
property
(
Acquisition
.
aq_chain
)
aq_parent
=
property
(
Acquisition
.
aq_parent
)
def
aq_acquire
(
self
,
*
args
,
**
kw
):
return
Acquisition
.
aq_acquire
(
self
,
*
args
,
**
kw
)
def
aq_inContextOf
(
self
,
*
args
,
**
kw
):
return
Acquisition
.
aq_inContextOf
(
self
,
*
args
,
**
kw
)
class
IBrowserDefault
(
Interface
):
"""Provide a hook for deciding about the default view for an object"""
...
...
lib/python/Products/Five/browser/__init__.py
View file @
17b5a358
...
...
@@ -18,8 +18,24 @@ $Id$
import
Acquisition
import
zope.publisher.browser
class
BrowserView
(
Acquisition
.
Explicit
,
zope
.
publisher
.
browser
.
BrowserView
):
"""Five browser view
from
Products.Five.bbb
import
AcquisitionBBB
Mixes in explicit acquisition so that security can be acquired for
views"""
class
BrowserView
(
zope
.
publisher
.
browser
.
BrowserView
,
AcquisitionBBB
):
# Use an explicit __init__ to work around problems with magically inserted
# super classes when using BrowserView as a base for viewlets.
def
__init__
(
self
,
context
,
request
):
zope
.
publisher
.
browser
.
BrowserView
.
__init__
(
self
,
context
,
request
)
# Classes which are still based on Acquisition and access
# self.context in a method need to call aq_inner on it, or get a
# funky aq_chain. We do this here for BBB friendly purposes.
def
__getParent
(
self
):
return
getattr
(
self
,
'_parent'
,
Acquisition
.
aq_inner
(
self
.
context
))
def
__setParent
(
self
,
parent
):
self
.
_parent
=
parent
aq_parent
=
__parent__
=
property
(
__getParent
,
__setParent
)
lib/python/Products/Five/browser/absoluteurl.py
View file @
17b5a358
...
...
@@ -15,24 +15,87 @@
$Id$
"""
import
urllib
from
Acquisition
import
aq_inner
,
aq_parent
from
OFS.interfaces
import
ITraversable
from
zope.interface
import
implements
from
zope.component
import
getMultiAdapter
from
zope.traversing.browser.interfaces
import
IAbsoluteURL
from
zope.traversing.browser.absoluteurl
import
_insufficientContext
,
_safe
from
Products.Five.browser
import
BrowserView
class
AbsoluteURL
(
BrowserView
):
"""An adapter for Zope3-style absolute_url using Zope2 methods
"""An absolute_url adapter for generic objects in Zope 2 that
aren't OFS.Traversable (e.g. views, resources, etc.).
(original: zope.traversing.browser.absoluteurl)
This is very close to the generic implementation from
zope.traversing.browser, but the Zope 2 request doesn't support
all the methods that it uses yet.
"""
implements
(
IAbsoluteURL
)
def
__init__
(
self
,
context
,
request
):
self
.
context
,
self
.
request
=
context
,
request
def
__unicode__
(
self
):
return
urllib
.
unquote
(
self
.
__str__
()).
decode
(
'utf-8'
)
def
__str__
(
self
):
context
=
self
.
context
request
=
self
.
request
container
=
aq_parent
(
context
)
if
container
is
None
:
raise
TypeError
(
_insufficientContext
)
url
=
str
(
getMultiAdapter
((
container
,
request
),
name
=
'absolute_url'
))
name
=
self
.
_getContextName
(
context
)
if
name
is
None
:
raise
TypeError
(
_insufficientContext
)
if
name
:
url
+=
'/'
+
urllib
.
quote
(
name
.
encode
(
'utf-8'
),
_safe
)
return
url
__call__
=
__str__
def
_getContextName
(
self
,
context
):
if
getattr
(
context
,
'getId'
,
None
)
is
not
None
:
return
context
.
getId
()
getattr
(
context
,
'__name__'
,
None
)
def
breadcrumbs
(
self
):
context
=
self
.
context
request
=
self
.
request
# We do this here do maintain the rule that we must be wrapped
container
=
aq_parent
(
context
)
if
container
is
None
:
raise
TypeError
(
_insufficientContext
)
base
=
tuple
(
getMultiAdapter
((
container
,
request
),
name
=
'absolute_url'
).
breadcrumbs
())
name
=
self
.
_getContextName
(
context
)
if
name
is
None
:
raise
TypeError
(
_insufficientContext
)
if
name
:
base
+=
({
'name'
:
name
,
'url'
:
(
"%s/%s"
%
(
base
[
-
1
][
'url'
],
urllib
.
quote
(
name
.
encode
(
'utf-8'
),
_safe
)))
},
)
return
base
class
OFSTraversableAbsoluteURL
(
BrowserView
):
"""An absolute_url adapter for OFS.Traversable subclasses
"""
implements
(
IAbsoluteURL
)
def
__unicode__
(
self
):
return
urllib
.
unquote
(
self
.
__str__
()).
decode
(
'utf-8'
)
def
__str__
(
self
):
context
=
aq_inner
(
self
.
context
)
...
...
@@ -47,10 +110,10 @@ class AbsoluteURL(BrowserView):
name
=
context
.
getId
()
if
container
is
None
or
self
.
_isVirtualHostRoot
()
\
or
not
ITraversable
.
providedBy
(
container
):
return
(
{
'name'
:
name
,
'url'
:
context
.
absolute_url
()},)
if
(
container
is
None
or
self
.
_isVirtualHostRoot
()
or
not
ITraversable
.
providedBy
(
container
)):
return
(
{
'name'
:
name
,
'url'
:
context
.
absolute_url
()},)
view
=
getMultiAdapter
((
container
,
request
),
IAbsoluteURL
)
base
=
tuple
(
view
.
breadcrumbs
())
...
...
@@ -66,15 +129,9 @@ class AbsoluteURL(BrowserView):
context
=
aq_inner
(
self
.
context
)
return
context
.
restrictedTraverse
(
virtualrootpath
)
==
context
class
SiteAbsoluteURL
(
AbsoluteURL
):
"""An adapter for Zope3-style absolute_url using Zope2 methods
This one is just used to stop breadcrumbs from crumbing up
to the Zope root.
(original: zope.traversing.browser.absoluteurl)
class
RootAbsoluteURL
(
OFSTraversableAbsoluteURL
):
"""An absolute_url adapter for the root object (OFS.Application)
"""
def
breadcrumbs
(
self
):
context
=
self
.
context
request
=
self
.
request
...
...
lib/python/Products/Five/browser/adding.py
View file @
17b5a358
...
...
@@ -23,6 +23,8 @@ $Id$
__docformat__
=
'restructuredtext'
from
warnings
import
warn
from
zope.component
import
getMultiAdapter
from
zope.component
import
getUtility
from
zope.component
import
queryMultiAdapter
...
...
@@ -41,15 +43,13 @@ from zope.app.container.interfaces import IAdding, INameChooser
from
zope.app.container.interfaces
import
IContainerNamesContainer
from
zope.app.publisher.browser.menu
import
getMenu
from
Acquisition
import
Implicit
from
zExceptions
import
BadRequest
from
OFS.SimpleItem
import
SimpleItem
from
Products.Five
import
BrowserView
from
Products.Five.browser.pagetemplatefile
import
ViewPageTemplateFile
class
Adding
(
Implicit
,
BrowserView
):
class
BasicAdding
(
BrowserView
):
implements
(
IAdding
,
IPublishTraverse
)
def
add
(
self
,
content
):
...
...
@@ -78,7 +78,7 @@ class Adding(Implicit, BrowserView):
# Invoke the name chooser even when we have a
# name. It'll do useful things with it like converting
# the incoming unicode to an ASCII string.
name
=
chooser
.
chooseName
(
name
,
cont
ent
)
name
=
chooser
.
chooseName
(
name
,
cont
ainer
)
content
.
id
=
name
container
.
_setObject
(
name
,
content
)
...
...
@@ -92,12 +92,18 @@ class Adding(Implicit, BrowserView):
# XXX this is definitely not right for all or even most uses
# of Five, but can be overridden by an AddView subclass, using
# the class attribute of a zcml:addform directive
return
absoluteURL
(
self
.
context
,
self
.
request
)
+
'/manage_main'
return
str
(
getMultiAdapter
((
self
.
context
,
self
.
request
),
name
=
u"absolute_url"
))
+
'/manage_main'
# set in BrowserView.__init__
request
=
None
context
=
None
def
renderAddButton
(
self
):
warn
(
"The renderAddButton method is deprecated, use nameAllowed"
,
DeprecationWarning
,
2
)
def
publishTraverse
(
self
,
request
,
name
):
"""See zope.publisher.interfaces.IPublishTraverse"""
if
'='
in
name
:
...
...
@@ -119,7 +125,7 @@ class Adding(Implicit, BrowserView):
factory
=
queryUtility
(
IFactory
,
name
)
if
factory
is
None
:
return
super
(
Adding
,
self
).
publishTraverse
(
request
,
name
)
return
super
(
Basic
Adding
,
self
).
publishTraverse
(
request
,
name
)
return
factory
...
...
@@ -135,10 +141,11 @@ class Adding(Implicit, BrowserView):
else
:
view_name
=
type_name
if
queryMultiAdapter
((
self
,
self
.
request
),
name
=
view_name
)
is
not
None
:
if
(
queryMultiAdapter
((
self
,
self
.
request
),
name
=
view_name
)
is
not
None
)
:
url
=
"%s/%s=%s"
%
(
absoluteURL
(
self
,
self
.
request
),
type_name
,
id
)
getMultiAdapter
((
self
,
self
.
request
),
name
=
u"absolute_url"
),
type_name
,
id
)
self
.
request
.
response
.
redirect
(
url
)
return
...
...
@@ -153,10 +160,16 @@ class Adding(Implicit, BrowserView):
self
.
add
(
content
)
self
.
request
.
response
.
redirect
(
self
.
nextURL
())
def
namesAccepted
(
self
):
return
not
IContainerNamesContainer
.
providedBy
(
self
.
context
)
def
nameAllowed
(
self
):
"""Return whether names can be input by the user."""
return
not
IContainerNamesContainer
.
providedBy
(
self
.
context
)
class
Adding
(
BasicAdding
):
menu_id
=
None
index
=
ViewPageTemplateFile
(
"adding.pt"
)
...
...
lib/python/Products/Five/browser/configure.zcml
View file @
17b5a358
...
...
@@ -39,16 +39,32 @@
/>
<browser:page
for="
zope.traversing.interfaces.IContainmentRoot
"
for="
OFS.interfaces.ITraversable
"
name="absolute_url"
class=".absoluteurl.
Sit
eAbsoluteURL"
class=".absoluteurl.
OFSTraversabl
eAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="zope.traversing.interfaces.IContainmentRoot"
factory=".absoluteurl.SiteAbsoluteURL"
for="OFS.interfaces.ITraversable"
factory=".absoluteurl.OFSTraversableAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="OFS.interfaces.IApplication"
name="absolute_url"
class=".absoluteurl.RootAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="OFS.interfaces.IApplication"
factory=".absoluteurl.RootAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.traversing.browser.interfaces.IAbsoluteURL"
...
...
lib/python/Products/Five/browser/metaconfigure.py
View file @
17b5a358
...
...
@@ -29,17 +29,17 @@ from zope.configuration.exceptions import ConfigurationError
from
zope.publisher.interfaces.browser
import
IBrowserRequest
,
\
IDefaultBrowserLayer
from
zope.app.publisher.browser.viewmeta
import
pages
as
zope_app_pages
from
zope.app.publisher.browser.viewmeta
import
view
as
zope_app_view
from
zope.app.publisher.browser.viewmeta
import
providesCallable
,
\
_handle_menu
,
_handle_for
import
zope.app.publisher.browser.viewmeta
import
zope.app.pagetemplate.simpleviewclass
from
zope.app.publisher.browser.viewmeta
import
(
providesCallable
,
_handle_menu
,
_handle_for
)
from
Products.Five.browser
import
BrowserView
from
Products.Five.browser.resource
import
FileResourceFactory
from
Products.Five.browser.resource
import
ImageResourceFactory
from
Products.Five.browser.resource
import
PageTemplateResourceFactory
from
Products.Five.browser.resource
import
DirectoryResourceFactory
from
Products.Five.browser.pagetemplatefile
import
ZopeTwo
PageTemplateFile
from
Products.Five.browser.pagetemplatefile
import
View
PageTemplateFile
from
Products.Five.metaclass
import
makeClass
from
Products.Five.security
import
getSecurityInfo
,
protectClass
,
protectName
from
Products.Five.security
import
CheckerPrivateId
...
...
@@ -159,7 +159,7 @@ def page(_context, name, permission, for_,
args
=
(
new_class
,)
)
class
pages
(
zope
_app_
pages
):
class
pages
(
zope
.
app
.
publisher
.
browser
.
viewmeta
.
pages
):
def
page
(
self
,
_context
,
name
,
attribute
=
'__call__'
,
template
=
None
,
menu
=
None
,
title
=
None
):
...
...
@@ -172,7 +172,7 @@ class pages(zope_app_pages):
# view (named view with pages)
class
view
(
zope
_app_
view
):
class
view
(
zope
.
app
.
publisher
.
browser
.
viewmeta
.
view
):
def
__call__
(
self
):
(
_context
,
name
,
for_
,
permission
,
layer
,
class_
,
...
...
@@ -185,7 +185,7 @@ class view(zope_app_view):
for
pname
,
attribute
,
template
in
self
.
pages
:
if
template
:
cdict
[
pname
]
=
ZopeTwo
PageTemplateFile
(
template
)
cdict
[
pname
]
=
View
PageTemplateFile
(
template
)
if
attribute
and
attribute
!=
name
:
cdict
[
attribute
]
=
cdict
[
pname
]
else
:
...
...
@@ -209,9 +209,9 @@ class view(zope_app_view):
view
=
component
.
queryMultiAdapter
((
self
,
request
),
name
=
name
,
default
=
None
)
if
view
is
not
None
:
return
view
.
__of__
(
self
)
return
view
m
=
class_
.
publishTraverse
.
__get__
(
self
)
.
__of__
(
self
)
m
=
class_
.
publishTraverse
.
__get__
(
self
)
return
m
(
request
,
name
)
else
:
...
...
@@ -223,7 +223,7 @@ class view(zope_app_view):
view
=
component
.
queryMultiAdapter
((
self
,
request
),
name
=
name
,
default
=
None
)
if
view
is
not
None
:
return
view
.
__of__
(
self
)
return
view
raise
NotFoundError
(
self
,
name
,
request
)
...
...
@@ -389,39 +389,29 @@ def resourceDirectory(_context, name, directory, layer=IDefaultBrowserLayer,
args
=
(
new_class
,)
)
#
# mixin classes / class factories
#
class
ViewMixinForAttributes
(
BrowserView
):
class
ViewMixinForAttributes
(
BrowserView
,
zope
.
app
.
publisher
.
browser
.
viewmeta
.
simple
):
# we have an attribute that we can simply tell ZPublisher to go to
def
__browser_default__
(
self
,
request
):
return
self
,
(
self
.
__page_attribute__
,)
# For some reason, the 'simple' baseclass doesn't implement this
# mandatory method (see https://bugs.launchpad.net/zope3/+bug/129296)
def
browserDefault
(
self
,
request
):
return
getattr
(
self
,
self
.
__page_attribute__
),
()
# this is technically not needed because ZPublisher finds our
# attribute through __browser_default__; but we also want to be
# able to call pages from python modules, PythonScripts or ZPT
__call__
=
property
(
lambda
self
:
getattr
(
self
,
self
.
__page_attribute__
))
class
ViewMixinForTemplates
(
BrowserView
):
# short cut to get to macros more easily
def
__getitem__
(
self
,
name
):
if
name
==
'macros'
:
return
self
.
index
.
macros
return
self
.
index
.
macros
[
name
]
# __call__ should have the same signature as the original method
@
property
def
__call__
(
self
):
return
getattr
(
self
,
self
.
__page_attribute__
)
# make the template publishable
def
__call__
(
self
,
*
args
,
**
kw
):
return
self
.
index
(
self
,
*
args
,
**
kw
)
class
ViewMixinForTemplates
(
BrowserView
,
zope
.
app
.
pagetemplate
.
simpleviewclass
.
simple
):
pass
def
makeClassForTemplate
(
filename
,
globals
=
None
,
used_for
=
None
,
bases
=
(),
cdict
=
None
,
name
=
u''
):
# XXX needs to deal with security from the bases?
if
cdict
is
None
:
cdict
=
{}
cdict
.
update
({
'index'
:
ZopeTwo
PageTemplateFile
(
filename
,
globals
),
cdict
.
update
({
'index'
:
View
PageTemplateFile
(
filename
,
globals
),
'__name__'
:
name
})
bases
+=
(
ViewMixinForTemplates
,)
class_
=
makeClass
(
"SimpleViewClass from %s"
%
filename
,
bases
,
cdict
)
...
...
lib/python/Products/Five/browser/pagetemplatefile.py
View file @
17b5a358
...
...
@@ -15,85 +15,84 @@
$Id$
"""
import
os
,
sys
from
os.path
import
basename
from
zope.app.pagetemplate
import
viewpagetemplatefile
from
Acquisition
import
aq_inner
from
Globals
import
package_home
from
Products.PageTemplates.PageTemplateFile
import
PageTemplateFile
from
Acquisition
import
aq_get
from
AccessControl
import
getSecurityManager
from
Products.PageTemplates.Expressions
import
SecureModuleImporter
from
Products.PageTemplates.Expressions
import
createTrustedZopeEngine
from
zope.app.pagetemplate.viewpagetemplatefile
import
ViewMapper
from
Products.Five.bbb
import
AcquisitionBBB
_engine
=
createTrustedZopeEngine
()
def
getEngine
():
return
_engine
class
ZopeTwoPageTemplateFile
(
PageTemplateFile
):
"""A strange hybrid between Zope 2 and Zope 3 page template.
Uses Zope 2's engine, but with security disabled and with some
initialization and API from Zope 3.
class
ViewPageTemplateFile
(
viewpagetemplatefile
.
ViewPageTemplateFile
):
"""Page Template used as class variable of views defined as Python classes.
"""
def
__init__
(
self
,
filename
,
_prefix
=
None
,
content_type
=
None
):
# XXX doesn't use content_type yet
def
getId
(
self
):
return
basename
(
self
.
filename
)
id
=
property
(
getId
)
def
__call__
(
self
,
__instance
,
*
args
,
**
keywords
):
instance
=
__instance
namespace
=
self
.
pt_getContext
(
request
=
instance
.
request
,
instance
=
instance
,
args
=
args
,
options
=
keywords
)
debug_flags
=
instance
.
request
.
debug
s
=
self
.
pt_render
(
namespace
,
showtal
=
getattr
(
debug_flags
,
'showTAL'
,
0
),
sourceAnnotations
=
getattr
(
debug_flags
,
'sourceAnnotations'
,
0
),
)
response
=
instance
.
request
.
response
if
not
response
.
getHeader
(
"Content-Type"
):
response
.
setHeader
(
"Content-Type"
,
self
.
content_type
)
return
s
self
.
ZBindings_edit
(
self
.
_default_bindings
)
def
pt_getEngine
(
self
):
return
getEngine
()
path
=
self
.
get_path_from_prefix
(
_prefix
)
self
.
filename
=
os
.
path
.
join
(
path
,
filename
)
if
not
os
.
path
.
isfile
(
self
.
filename
):
raise
ValueError
(
"No such file"
,
self
.
filename
)
def
pt_getContext
(
self
,
instance
,
request
,
**
kw
):
context
=
super
(
ViewPageTemplateFile
,
self
).
pt_getContext
(
instance
,
request
,
**
kw
)
basepath
,
ext
=
os
.
path
.
splitext
(
self
.
filename
)
self
.
__name__
=
os
.
path
.
basename
(
basepath
)
# get the root
obj
=
context
[
'context'
]
root
=
None
meth
=
aq_get
(
obj
,
'getPhysicalRoot'
,
None
)
if
meth
is
not
None
:
root
=
meth
()
super
(
PageTemplateFile
,
self
).
__init__
(
self
.
filename
,
_prefix
)
context
.
update
(
here
=
context
[
'context'
],
# philiKON thinks container should be the view,
# but BBB is more important than aesthetics.
container
=
context
[
'context'
],
root
=
root
,
modules
=
SecureModuleImporter
,
traverse_subpath
=
[],
# BBB, never really worked
user
=
getSecurityManager
().
getUser
()
)
return
context
def
get_path_from_prefix
(
self
,
_prefix
):
if
isinstance
(
_prefix
,
str
):
path
=
_prefix
else
:
if
_prefix
is
None
:
_prefix
=
sys
.
_getframe
(
2
).
f_globals
path
=
package_home
(
_prefix
)
return
path
def
__get__
(
self
,
instance
,
type
):
return
BoundPageTemplate
(
self
,
instance
)
# When a view's template is accessed e.g. as template.view, a
# BoundPageTemplate object is retured. For BBB reasons, it needs to
# support the aq_* methods and attributes known from Acquisition. For
# that it also needs to be locatable thru __parent__.
class
BoundPageTemplate
(
viewpagetemplatefile
.
BoundPageTemplate
,
AcquisitionBBB
):
__parent__
=
property
(
lambda
self
:
self
.
im_self
)
def
pt_getEngine
(
self
):
return
getEngine
()
def
pt_getContext
(
self
):
try
:
root
=
self
.
getPhysicalRoot
()
except
AttributeError
:
try
:
root
=
self
.
context
.
getPhysicalRoot
()
except
AttributeError
:
root
=
None
# Even if the context isn't a view (when would that be exaclty?),
# there shouldn't be any dange in applying a view, because it
# won't be used. However assuming that a lack of getPhysicalRoot
# implies a missing view causes problems.
view
=
self
.
_getContext
()
here
=
aq_inner
(
self
.
context
)
request
=
getattr
(
root
,
'REQUEST'
,
None
)
c
=
{
'template'
:
self
,
'here'
:
here
,
'context'
:
here
,
'container'
:
here
,
'nothing'
:
None
,
'options'
:
{},
'root'
:
root
,
'request'
:
request
,
'modules'
:
SecureModuleImporter
,
}
if
view
is
not
None
:
c
[
'view'
]
=
view
c
[
'views'
]
=
ViewMapper
(
here
,
request
)
return
c
ViewPageTemplateFile
=
ZopeTwoPageTemplateFile
# BBB
ZopeTwoPageTemplateFile
=
ViewPageTemplateFile
lib/python/Products/Five/browser/providerexpression.py
View file @
17b5a358
...
...
@@ -12,21 +12,23 @@
#
##############################################################################
"""Provider expression.
$Id$
"""
import
zope.event
import
zope.interface
import
zope.component
from
zope.contentprovider
import
interfaces
as
cp_interfaces
from
zope.contentprovider.tales
import
addTALNamespaceData
from
zope.interface
import
implements
from
zope.tales.expressions
import
StringExpr
class
Z2ProviderExpression
(
StringExpr
):
"""Create a custom provider expression which overrides __call__ to
acquisition wrap the provider so that security lookups can be done."""
from
zope.tales
import
expressions
from
zope.contentprovider
import
interfaces
,
tales
from
zope.location.interfaces
import
ILocation
from
Acquisition.interfaces
import
IAcquirer
implements
(
cp_interfaces
.
ITALESProviderExpression
)
class
Z2ProviderExpression
(
expressions
.
StringExpr
):
zope
.
interface
.
implements
(
interfaces
.
ITALESProviderExpression
)
# This is mostly a copy of
# zope.contentprovider.tales.TALESProviderExpression's __call__
# method.
def
__call__
(
self
,
econtext
):
name
=
super
(
Z2ProviderExpression
,
self
).
__call__
(
econtext
)
context
=
econtext
.
vars
[
'context'
]
...
...
@@ -35,19 +37,26 @@ class Z2ProviderExpression(StringExpr):
# Try to look up the provider.
provider
=
zope
.
component
.
queryMultiAdapter
(
(
context
,
request
,
view
),
cp_
interfaces
.
IContentProvider
,
name
)
(
context
,
request
,
view
),
interfaces
.
IContentProvider
,
name
)
# Provide a useful error message, if the provider was not found.
if
provider
is
None
:
raise
cp_interfaces
.
ContentProviderLookupError
(
name
)
raise
interfaces
.
ContentProviderLookupError
(
name
)
# add the __name__ attribute if it implements ILocation
if
ILocation
.
providedBy
(
provider
):
provider
.
__name__
=
name
if
getattr
(
provider
,
'__of__'
,
None
)
is
not
None
:
# ATTN: This is where we are different from
# TALESProviderExpression: We support Acquisition wrapping.
if
IAcquirer
.
providedBy
(
provider
):
provider
=
provider
.
__of__
(
context
)
# Insert the data gotten from the context
addTALNamespaceData
(
provider
,
econtext
)
tales
.
addTALNamespaceData
(
provider
,
econtext
)
# Stage 1: Do the state update.
zope
.
event
.
notify
(
interfaces
.
BeforeUpdateEvent
(
provider
,
request
))
provider
.
update
()
# Stage 2: Render the HTML content.
...
...
lib/python/Products/Five/browser/resource.py
View file @
17b5a358
...
...
@@ -18,111 +18,60 @@ $Id$
import
os
import
urllib
import
Acquisition
from
OFS.Traversable
import
Traversable
as
OFSTraversable
from
zope.app.publisher.browser.resources
import
empty
from
zope.app.publisher.fileresource
import
File
,
Image
from
zope.app.publisher.pagetemplateresource
import
PageTemplate
from
zope.interface
import
implements
from
zope.component
import
getMultiAdapter
from
zope.component.interfaces
import
IResource
from
zope.datetime
import
time
as
timeFromDateTimeString
from
zope.traversing.browser.interfaces
import
IAbsoluteURL
from
zope.traversing.browser
import
absoluteURL
from
zope.publisher.interfaces
import
NotFound
from
zope.publisher.interfaces.browser
import
IBrowserPublisher
from
zope.app.publisher.browser
import
fileresource
,
directoryresource
from
zope.app.publisher.fileresource
import
File
,
Image
from
zope.app.publisher.pagetemplateresource
import
PageTemplate
from
Products.Five.browser
import
BrowserView
_marker
=
[]
class
Resource
(
Acquisition
.
Explicit
):
"""A publishable resource
"""
implements
(
IResource
)
_marker
=
object
()
class
Resource
(
object
):
"""A mixin that changes the URL-rendering of resources (__call__).
def
__init__
(
self
,
request
):
self
.
request
=
request
In Zope 3, resource URLs are of the form
nearest_site/@@/resource_name. Since Zope 2 didn't have support
for sites from the beginning of the Five integration, resource
URLs in Zope 2 are of the form context/++resource++resource_name.
TODO It would be good if that could be changed in the long term,
thus making this mixin (and probably the other classes in this
module) obsolete.
"""
def
__call__
(
self
):
name
=
self
.
__name__
container
=
self
.
__parent__
# TODO Zope 3 uses site = getSite() instead of container here
# and the @@ resource access view
url
=
str
(
getMultiAdapter
((
container
,
self
.
request
),
IAbsoluteURL
))
url
=
urllib
.
unquote
(
url
)
url
=
urllib
.
unquote
(
absoluteURL
(
container
,
self
.
request
))
if
not
isinstance
(
container
,
DirectoryResource
):
name
=
'++resource++%s'
%
name
return
"%s/%s"
%
(
url
,
name
)
class
PageTemplateResource
(
BrowserView
,
Resource
):
#implements(IBrowserPublisher)
class
PageTemplateResource
(
Resource
,
BrowserView
):
implements
(
IBrowserPublisher
)
def
browserDefault
(
self
,
request
):
return
self
.
render
,
()
def
__browser_default__
(
self
,
request
):
r
eturn
self
,
(
'render'
,
)
def
publishTraverse
(
self
,
request
,
name
):
r
aise
NotFound
(
self
,
name
,
request
)
def
render
(
self
):
"""Rendered content"""
# ZPublisher might have called setBody with an incorrect URL
# we definitely don't want that if we are plain html
self
.
request
.
RESPONSE
.
setBase
(
None
)
self
.
request
.
response
.
setBase
(
None
)
pt
=
self
.
context
return
pt
(
self
.
request
)
class
FileResource
(
BrowserView
,
Resource
):
"""A publishable file-based resource"""
#implements(IBrowserPublisher)
def
__browser_default__
(
self
,
request
):
return
self
,
(
request
.
REQUEST_METHOD
,)
def
GET
(
self
):
"""Default content"""
file
=
self
.
context
request
=
self
.
request
response
=
request
.
response
# HTTP If-Modified-Since header handling. This is duplicated
# from OFS.Image.Image - it really should be consolidated
# somewhere...
header
=
request
.
environ
.
get
(
'If-Modified-Since'
,
None
)
if
header
is
not
None
:
header
=
header
.
split
(
';'
)[
0
]
# Some proxies seem to send invalid date strings for this
# header. If the date string is not valid, we ignore it
# rather than raise an error to be generally consistent
# with common servers such as Apache (which can usually
# understand the screwy date string as a lucky side effect
# of the way they parse it).
try
:
mod_since
=
long
(
timeFromDateTimeString
(
header
))
except
:
mod_since
=
None
if
mod_since
is
not
None
:
if
getattr
(
file
,
'lmt'
,
None
):
last_mod
=
long
(
file
.
lmt
)
else
:
last_mod
=
long
(
0
)
if
last_mod
>
0
and
last_mod
<=
mod_since
:
response
.
setStatus
(
304
)
return
''
response
.
setHeader
(
'Content-Type'
,
file
.
content_type
)
response
.
setHeader
(
'Last-Modified'
,
file
.
lmh
)
# Cache for one day
response
.
setHeader
(
'Cache-Control'
,
'public,max-age=86400'
)
f
=
open
(
file
.
path
,
'rb'
)
data
=
f
.
read
()
f
.
close
()
return
data
def
HEAD
(
self
):
file
=
self
.
context
response
=
self
.
request
.
response
response
=
self
.
request
.
response
response
.
setHeader
(
'Content-Type'
,
file
.
content_type
)
response
.
setHeader
(
'Last-Modified'
,
file
.
lmh
)
# Cache for one day
response
.
setHeader
(
'Cache-Control'
,
'public,max-age=86400'
)
return
''
class
FileResource
(
Resource
,
fileresource
.
FileResource
):
pass
class
ResourceFactory
:
...
...
@@ -173,8 +122,7 @@ class Directory:
self
.
path
=
path
self
.
__name__
=
name
class
DirectoryResource
(
BrowserView
,
Resource
,
OFSTraversable
):
#implements(IBrowserPublisher)
class
DirectoryResource
(
Resource
,
directoryresource
.
DirectoryResource
):
resource_factories
=
{
'gif'
:
ImageResourceFactory
,
...
...
@@ -187,28 +135,12 @@ class DirectoryResource(BrowserView, Resource, OFSTraversable):
default_factory
=
FileResourceFactory
def
__init__
(
self
,
context
,
request
):
BrowserView
.
__init__
(
self
,
context
,
request
)
# OFSTraversable.absolute_url() assumes self.REQUEST being
# accessible:
self
.
REQUEST
=
request
def
getId
(
self
):
name
=
self
.
__name__
if
not
name
.
startswith
(
'++resource++'
):
name
=
'++resource++%s'
%
self
.
__name__
return
name
def
__browser_default__
(
self
,
request
):
'''See interface IBrowserPublisher'''
return
empty
,
()
def
__getitem__
(
self
,
name
):
res
=
self
.
get
(
name
,
None
)
if
res
is
None
:
raise
KeyError
,
name
return
res
def
get
(
self
,
name
,
default
=
_marker
):
path
=
self
.
context
.
path
filename
=
os
.
path
.
join
(
path
,
name
)
...
...
@@ -229,11 +161,7 @@ class DirectoryResource(BrowserView, Resource, OFSTraversable):
resource
=
factory
(
name
,
filename
)(
self
.
request
)
resource
.
__name__
=
name
resource
.
__parent__
=
self
# XXX __of__ wrapping is usually done on traversal.
# However, we don't want to subclass Traversable (or do we?)
# The right thing should probably be a specific (and very simple)
# traverser that does __getitem__ and __of__.
return
resource
.
__of__
(
self
)
return
resource
class
DirectoryResourceFactory
(
ResourceFactory
):
...
...
lib/python/Products/Five/browser/tests/aqlegacy.py
0 → 100644
View file @
17b5a358
##############################################################################
#
# Copyright (c) 2007 Zope Corporation 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.
#
##############################################################################
"""Legacy browser view tests.
Here we nake sure that legacy implementations of views (e.g. those
which mix-in one of the Acquisition base classes without knowing
better) still work.
"""
import
Acquisition
import
OFS.SimpleItem
from
zope.interface
import
implements
from
zope.traversing.interfaces
import
ITraversable
from
zope.contentprovider.interfaces
import
IContentProvider
from
Products.Five
import
BrowserView
from
Products.Five.browser.pagetemplatefile
import
ViewPageTemplateFile
class
LegacyAttributes
(
BrowserView
):
"""Make sure that those old aq_* attributes on Five BrowserViews
still work, in particular aq_chain, even though BrowserView may
not be an Acquisition-decendant class anymore...
"""
def
__call__
(
self
):
return
repr
([
obj
for
obj
in
self
.
aq_chain
])
class
ExplicitLegacyAttributes
(
Acquisition
.
Explicit
):
"""Make sure that those old aq_* attributes work on browser views
that only inherit from Explicit as well."""
def
__call__
(
self
):
return
repr
([
obj
for
obj
in
self
.
aq_chain
])
class
LegacyTemplate
(
BrowserView
):
template
=
ViewPageTemplateFile
(
'falcon.pt'
)
def
__call__
(
self
):
return
self
.
template
()
class
LegacyTemplateTwo
(
BrowserView
):
def
__init__
(
self
,
context
,
request
):
self
.
__parent__
=
context
self
.
context
=
context
self
.
request
=
request
self
.
template
=
ViewPageTemplateFile
(
'falcon.pt'
)
def
__call__
(
self
):
return
self
.
template
()
class
Explicit
(
Acquisition
.
Explicit
):
def
render
(
self
):
return
'Explicit'
class
ExplicitWithTemplate
(
Acquisition
.
Explicit
):
template
=
ViewPageTemplateFile
(
'falcon.pt'
)
class
Implicit
(
Acquisition
.
Implicit
):
def
render
(
self
):
return
'Implicit'
class
ImplicitWithTemplate
(
Acquisition
.
Implicit
):
template
=
ViewPageTemplateFile
(
'falcon.pt'
)
class
ExplicitContentProvider
(
Acquisition
.
Explicit
):
implements
(
IContentProvider
)
def
__init__
(
self
,
context
,
request
,
view
):
self
.
context
=
context
self
.
request
=
request
self
.
view
=
view
# Normally, a content provider should set __parent__ to view
# or context. This one doesn't do this on purpose to ensure
# it works without.
def
update
(
self
):
# Make sure that the content provider is acquisition wrapped.
assert
self
.
aq_parent
==
self
.
context
assert
self
.
aq_base
==
self
def
render
(
self
):
return
'Content provider inheriting from Explicit'
class
ExplicitViewlet
(
Acquisition
.
Explicit
):
def
__init__
(
self
,
context
,
request
,
view
,
manager
):
self
.
context
=
context
self
.
request
=
request
def
update
(
self
):
# Make sure that the viewlet has the legacy attributes and
# they point to the right objects.
assert
self
.
aq_parent
==
self
.
context
assert
self
.
aq_base
==
self
def
render
(
self
):
return
'Viewlet inheriting from Explicit'
class
BrowserViewViewlet
(
BrowserView
):
def
__init__
(
self
,
context
,
request
,
view
,
manager
):
# This is the tricky bit. super(...).__init__ wouldn't
# necessarily have to resolve to BrowserView.__init__ because
# <browser:viewlet /> generates classes on the fly with a
# mix-in base class...
super
(
BrowserViewViewlet
,
self
).
__init__
(
context
,
request
)
self
.
view
=
view
self
.
manager
=
manager
def
update
(
self
):
pass
def
render
(
self
):
return
'BrowserView viewlet'
class
LegacyNamespace
(
object
):
implements
(
ITraversable
)
def
__init__
(
self
,
context
,
request
):
self
.
context
=
context
self
.
request
=
request
def
traverse
(
self
,
name
,
ignored
):
return
LegacyNamespaceObject
(
name
)
class
LegacyNamespaceObject
(
OFS
.
SimpleItem
.
SimpleItem
):
def
__init__
(
self
,
name
):
self
.
id
=
name
lib/python/Products/Five/browser/tests/aqlegacy.zcml
0 → 100644
View file @
17b5a358
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
for="*"
name="attributes"
class=".aqlegacy.LegacyAttributes"
permission="zope.Public"
/>
<browser:page
for="*"
name="explicitattributes"
class=".aqlegacy.ExplicitLegacyAttributes"
permission="zope.Public"
/>
<browser:page
for="*"
name="template"
class=".aqlegacy.LegacyTemplate"
permission="zope.Public"
/>
<browser:page
for="*"
name="template_two"
class=".aqlegacy.LegacyTemplateTwo"
permission="zope.Public"
/>
<browser:page
for="*"
name="explicit"
class=".aqlegacy.Explicit"
attribute="render"
permission="zope.Public"
/>
<browser:page
for="*"
name="explicit_zcmltemplate"
class=".aqlegacy.Explicit"
template="falcon.pt"
permission="zope.Public"
/>
<browser:page
for="*"
name="explicit_template"
class=".aqlegacy.ExplicitWithTemplate"
attribute="template"
permission="zope.Public"
/>
<browser:page
for="*"
name="implicit"
class=".aqlegacy.Implicit"
attribute="render"
permission="zope.Public"
/>
<browser:page
for="*"
name="implicit_template"
class=".aqlegacy.ImplicitWithTemplate"
attribute="template"
permission="zope.Public"
/>
<browser:page
for="*"
name="implicit_zcmltemplate"
class=".aqlegacy.Implicit"
template="falcon.pt"
permission="zope.Public"
/>
<!-- Content providers and viewlets -->
<adapter
for="* * *"
provides="zope.contentprovider.interfaces.IContentProvider"
factory=".aqlegacy.ExplicitContentProvider"
name="aqlegacyprovider"
/>
<browser:page
for="*"
name="aqlegacyprovider"
template="legacyprovider.pt"
permission="zope.Public"
/>
<browser:viewletManager
name="aqlegacymanager"
permission="zope.Public"
/>
<browser:viewlet
for="*"
class=".aqlegacy.ExplicitViewlet"
name="explicit"
permission="zope.Public"
/>
<browser:viewlet
for="*"
class=".aqlegacy.BrowserViewViewlet"
name="browserview"
permission="zope.Public"
/>
<browser:page
for="*"
name="aqlegacymanager"
template="legacymanager.pt"
permission="zope.Public"
/>
<!-- Namespace traversal -->
<adapter
for="*"
factory=".aqlegacy.LegacyNamespace"
name="aqlegacy"
/>
<adapter
for="* *"
factory=".aqlegacy.LegacyNamespace"
name="aqlegacy"
/>
<browser:page
for=".aqlegacy.LegacyNamespaceObject"
name="index.html"
template="falcon.pt"
permission="zope.Public"
/>
</configure>
\ No newline at end of file
lib/python/Products/Five/browser/tests/aqlegacy_ftest.txt
0 → 100644
View file @
17b5a358
Testing legacy browser views
============================
This test tests publishing aspects of browser pages. Let's register
some:
>>> import Products.Five.browser.tests
>>> from Products.Five import zcml
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config('aqlegacy.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.testbrowser import Browser
>>> browser = Browser()
>>> browser.handleErrors = False
Acquisition API legacy on BrowserView
-------------------------------------
Let's make sure that accessing those old aq_* properties on browser
views still works (the printed output is the aq_chain of the view):
>>> browser.open('http://localhost/test_folder_1_/attributes')
>>> print browser.contents
[<Products.Five.metaclass.LegacyAttributes object at ...>,
<Folder at /test_folder_1_>,
<Application at >,
<ZPublisher.BaseRequest.RequestContainer object at ...>]
The same goes for browser views that just mix in Acquisition.Explicit:
>>> browser.open('http://localhost/test_folder_1_/explicitattributes')
>>> print browser.contents
[<Products.Five.metaclass.ExplicitLegacyAttributes object at ...>,
<Folder at /test_folder_1_>,
<Application at >,
<ZPublisher.BaseRequest.RequestContainer object at ...>]
Let's do some more manual tests with the view object. But first we
must get it:
>>> from zope.component import getMultiAdapter
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = getMultiAdapter((self.folder, request), name='attributes')
Let's check for the various aq_* attributes:
>>> view.aq_parent == self.folder
True
>>> view.aq_inner == view
True
>>> view.aq_base == view
True
>>> view.aq_self == view
True
Let's try to acquire something from the root folder:
>>> button = view.aq_acquire('ZopeAttributionButton')
>>> print button()
<a href="http://www.zope.org/Credits" target="_top"><img src="http://nohost/p_/ZopeButton" width="115" height="50" border="0" alt="Powered by Zope" /></a>
Let's check that we're in the right context:
>>> view.aq_inContextOf(self.folder)
1
>>> view.aq_inContextOf(self.app)
1
>>> view.aq_inContextOf(object())
0
Views also still support the __of__ protocol, at least pro forma:
>>> view == view.__of__(self.app)
True
Acquisition API legacy on a browser view's template
---------------------------------------------------
A view's template will also support the various aq_* attributes:
>>> view = getMultiAdapter((self.folder, request), name='template')
>>> template = view.template
>>> template.aq_parent == view
True
>>> template.aq_inner == template
True
>>> template.aq_base == template
True
>>> template.aq_self == template
True
>>> button = template.aq_acquire('ZopeAttributionButton')
>>> print button()
<a href="http://www.zope.org/Credits" target="_top"><img src="http://nohost/p_/ZopeButton" width="115" height="50" border="0" alt="Powered by Zope" /></a>
Mixing in Acquisition.{Ex|Im}plicit
-----------------------------------
Let's make sure that mixing in Acquisition.Explicit or Implicit won't
mess up your views (even though you should never have done it in the
first place...):
>>> browser.open('http://localhost/test_folder_1_/explicit')
>>> print browser.contents
Explicit
>>> browser.open('http://localhost/test_folder_1_/explicit_zcmltemplate')
>>> print browser.contents
<p>The falcon has taken flight</p>
>>> browser.open('http://localhost/test_folder_1_/explicit_template')
>>> print browser.contents
<p>The falcon has taken flight</p>
>>> browser.open('http://localhost/test_folder_1_/implicit')
>>> print browser.contents
Implicit
>>> browser.open('http://localhost/test_folder_1_/implicit_template')
>>> print browser.contents
<p>The falcon has taken flight</p>
>>> browser.open('http://localhost/test_folder_1_/implicit_zcmltemplate')
>>> print browser.contents
<p>The falcon has taken flight</p>
Testing legacy content providers and viewlets
=============================================
>>> browser.open('http://localhost/test_folder_1_/aqlegacyprovider')
>>> print browser.contents
<p>Content provider inheriting from Explicit</p>
>>> browser.open('http://localhost/test_folder_1_/aqlegacymanager')
>>> print browser.contents
<p>BrowserView viewlet
Viewlet inheriting from Explicit</p>
Testing namespace traversal
===========================
Namespace traversal can turn up objects during traversal without
attribute access. That means they might not be wrapped by default.
Here we make sure that they are wrapped and that things like the
request can be acquired.
First let's try ``restrictedTraverse()``:
>>> foo = self.folder.restrictedTraverse('++aqlegacy++foo')
>>> import Acquisition
>>> Acquisition.aq_acquire(foo, 'REQUEST')
<HTTPRequest, URL=http://nohost>
Now let's try URL traversal:
>>> browser.open('http://localhost/test_folder_1_/++aqlegacy++foo/index.html')
>>> print browser.contents
<p>The falcon has taken flight</p>
Testing keyword arguments
=========================
ViewPageTemplateFile's take arbitrary keyword arguments:
>>> view = getMultiAdapter((self.folder, request), name='template')
>>> template = view.template
>>> print template(foo=1, bar=2)
<p>The falcon has taken flight</p>
Passing in an argument called instance was supported by the old Five version
of ViewPageTemplateFile, so we still need to support it.
In the zope.app.pagetemplate version, the first required argument is called
instance, though.
>>> print template(instance='allowed')
<p>The falcon has taken flight</p>
No arguments required
=====================
ViewPageTemplateFile's require no arguments, but you can only use them as
class variables:
>>> view = getMultiAdapter((self.folder, request), name='template_two')
>>> print view()
Traceback (most recent call last):
...
TypeError: __call__() takes at least 2 arguments (1 given)
Clean up
--------
>>> from zope.app.testing.placelesssetup import tearDown
>>> tearDown()
lib/python/Products/Five/browser/tests/legacymanager.pt
0 → 100644
View file @
17b5a358
<p tal:content="provider:aqlegacymanager" />
lib/python/Products/Five/browser/tests/legacyprovider.pt
0 → 100644
View file @
17b5a358
<p tal:content="provider:aqlegacyprovider" />
lib/python/Products/Five/browser/tests/pages.py
View file @
17b5a358
...
...
@@ -16,6 +16,7 @@
$Id$
"""
from
Products.Five
import
BrowserView
from
Products.Five.browser.pagetemplatefile
import
ViewPageTemplateFile
class
SimpleView
(
BrowserView
):
"""More docstring. Please Zope"""
...
...
@@ -39,6 +40,10 @@ class CallView(BrowserView):
def
__call__
(
self
):
return
u"I was __call__()'ed"
class
CallTemplate
(
BrowserView
):
__call__
=
ViewPageTemplateFile
(
'falcon.pt'
)
class
CallableNoDocstring
:
def
__call__
(
self
):
...
...
@@ -58,7 +63,7 @@ class NoDocstringView(BrowserView):
class
NewStyleClass
(
object
):
"""
This is a testclass to verify that new style classes
are ignored
This is a testclass to verify that new style classes
work
in browser:page
"""
...
...
lib/python/Products/Five/browser/tests/pages.txt
View file @
17b5a358
...
...
@@ -157,7 +157,7 @@ Make sure that global template variables in ZPT pages are correct:
>>> print view()
View is a view: True
Context is testoid: True
Cont
a
xt.aq_parent is test_folder_1_: True
Cont
e
xt.aq_parent is test_folder_1_: True
Container is context: True
Here is context: True
Nothing is None: True
...
...
@@ -215,36 +215,42 @@ high-level security tests). Let's manually look up a protected view:
It's protecting the object with the permission, and not the attribute,
so we get ('',) instead of ('eagle',):
>>>
getattr(view, '__ac_permissions__')
>>>
view.__ac_permissions__
(('View management screens', ('',)),)
Wrap into an acquisition so that imPermissionRole objects can be
evaluated. __roles__ is a imPermissionRole object:
The view's __roles__ attribute can be evaluated correctly:
>>> view = view.__of__(self.folder.testoid)
>>> view_roles = getattr(view, '__roles__', None)
>>> view_roles
(We have to use aq_acquire here instead of a simple getattr. The
reason is that __roles__ actually is an object that expects being
called through the __of__ protocol upon which it renders the roles
tuple. aq_acquire will trigger this for us. This isn't a problem,
really, because AccessControl ends up using aq_acquire anyway, so it
Just Works.)
>>> from Acquisition import aq_acquire
>>> aq_acquire(view, '__roles__')
('Manager',)
Check to see if view's context properly acquires its true
parent
>>> from Acquisition import aq_parent, aq_base, aq_inner
>>> context =
getattr(view, 'context')
>>> context =
view.context
Check the wrapper type
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> type(context) == ImplicitAcquisitionWrapper
True
The acquired parent is the view. This isn't
usually what you want.
>>> aq_parent(context) == view
True
The parent of the view is the view's context:
>>> view.__parent__ == view.context
True
>>> aq_parent(view) == view.context
True
T
o get what you usually want, do this
T
he direct parent of the context is
>>> context.aq_inner.aq_parent
<Folder at /test_folder_1_>
...
...
lib/python/Products/Five/browser/tests/pages.zcml
View file @
17b5a358
...
...
@@ -161,6 +161,13 @@
permission="zope2.Public"
/>
<browser:page
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
class=".pages.CallTemplate"
name="calltemplate.html"
permission="zope2.Public"
/>
<!-- pages from methods/functions/callables that don't have docstrings -->
<browser:pages
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
...
...
lib/python/Products/Five/browser/tests/pages_ftest.txt
View file @
17b5a358
...
...
@@ -144,6 +144,14 @@ class bearing only a __call__ method:
...
I was __call__()'ed
or a __call__ object that's callable, such as a ViewPageTemplateFile:
>>> print http(r'''
... GET /test_folder_1_/testoid/calltemplate.html HTTP/1.1
... ''')
HTTP/1.1 200 OK
...
<p>The falcon has taken flight</p>
Clean up
--------
...
...
lib/python/Products/Five/browser/tests/provider.txt
View file @
17b5a358
...
...
@@ -188,18 +188,15 @@ information is used:
</body>
</html>
Now we test a provider using a PageTemplateFile to render itself. It must
inherit from an Acquisition base class so that the template can use Zope 2
security mechanisms:
Now we test a provider using a PageTemplateFile to render itself:
>>> import os, tempfile
>>> temp_dir = tempfile.mkdtemp()
>>> dynTemplate = os.path.join(temp_dir, 'dynamic_template.pt')
>>> open(dynTemplate, 'w').write(
... 'A simple template: <tal:simple replace="python:view.my_property" />')
>>> from Acquisition import Explicit
>>> from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
>>> class TemplateProvider(
Explici
t):
>>> class TemplateProvider(
objec
t):
... zope.component.adapts(zope.interface.Interface,
... browser.IDefaultBrowserLayer,
... zope.interface.Interface)
...
...
lib/python/Products/Five/browser/tests/resource_ftest.txt
View file @
17b5a358
...
...
@@ -33,6 +33,15 @@ Image resource
HTTP/1.1 200 OK
...
Image resources can't be traversed further:
>>> print http(r'''
... GET /test_folder_1_/testoid/++resource++pattern.png/more HTTP/1.1
... Authorization: Basic manager:r00t
... ''')
HTTP/1.1 404 Not Found
...
File resource
~~~~~~~~~~~~~
...
...
@@ -43,6 +52,15 @@ File resource
HTTP/1.1 200 OK
...
File resources can't be traversed further:
>>> print http(r'''
... GET /test_folder_1_/testoid/++resource++style.css/more HTTP/1.1
... Authorization: Basic manager:r00t
... ''')
HTTP/1.1 404 Not Found
...
Template resource
~~~~~~~~~~~~~~~~~
...
...
@@ -53,6 +71,15 @@ Template resource
HTTP/1.1 200 OK
...
Template resources can't be traversed further:
>>> print http(r'''
... GET /test_folder_1_/testoid/++resource++cockatiel.html/more HTTP/1.1
... Authorization: Basic manager:r00t
... ''')
HTTP/1.1 404 Not Found
...
Resource directory
~~~~~~~~~~~~~~~~~~
...
...
@@ -66,18 +93,6 @@ Page templates aren't guaranteed to render, so exclude them from the test:
... self.assertEquals(200, response.getStatus())
We also can traverse into sub-directories:
>>> print http(r'''
... GET /test_folder_1_/testoid/++resource++fivetest_resources/resource_subdir/resource.txt HTTP/1.1
... Authorization: Basic manager:r00t
... ''')
HTTP/1.1 200 OK
...
This is a resource in a subdirectory of a normal resource to test traversal.
<BLANKLINE>
We also can traverse into sub-directories:
>>> print http(r'''
...
...
@@ -105,6 +120,13 @@ We also can traverse into sub-directories:
</html>
<BLANKLINE>
>>> print http(r'''
... GET /test_folder_1_/testoid/++resource++fivetest_resources/resource_subdir/not-existant HTTP/1.1
... Authorization: Basic manager:r00t
... ''')
HTTP/1.1 404 Not Found
...
Clean up
--------
...
...
lib/python/Products/Five/browser/tests/template_variables.pt
View file @
17b5a358
View is a view: <tal:block
content="python:hasattr(view,'context') and hasattr(view, 'request')" />
Context is testoid: <tal:block content="python:context.id == 'testoid'" />
Cont
a
xt.aq_parent is test_folder_1_: <tal:block
Cont
e
xt.aq_parent is test_folder_1_: <tal:block
content="python:context.aq_parent.id =='test_folder_1_'" />
Container is context: <tal:block content="python:container is context" />
Here is context: <tal:block content="python:here is context"/>
...
...
@@ -10,7 +10,7 @@ Default works: <tal:block replace="non_existent_var|default" />True
Root is the application: <tal:block
replace="python:repr(root).find('Application') != -1" />
Template is a template: <tal:block
replace="python:
repr(template.aq_base).startswith('<ZopeTwoPageTemplateFile'
)" />
replace="python:
'ViewPageTemplateFile' in repr(template
)" />
Traverse_subpath exists and is empty: <tal:block
replace="python:traverse_subpath == []" />
Request is a request: <tal:block
...
...
lib/python/Products/Five/browser/tests/test_absoluteurl.py
View file @
17b5a358
...
...
@@ -51,12 +51,11 @@ def test_absoluteurl():
This test assures and demonstrates that the absolute url stops
traversing through an object's parents when it has reached the
root object. In Zope 3 this is marked with the IContainmentRoot
interface:
root object.
>>> from zope.interface import
directlyProvides, providedBy
>>> from
zope.traversing.interfaces import IContainmentRoot
>>>
directlyProvides(self.folder, IContainmentRoot
)
>>> from zope.interface import
alsoProvides, noLongerProvides
>>> from
OFS.interfaces import IApplication
>>>
alsoProvides(self.folder, IApplication
)
>>> for crumb in view.breadcrumbs():
... info = crumb.items()
...
...
@@ -65,8 +64,7 @@ def test_absoluteurl():
[('name', 'test_folder_1_'), ('url', 'http://nohost/test_folder_1_')]
[('name', 'testoid'), ('url', 'http://nohost/test_folder_1_/testoid')]
>>> directlyProvides(self.folder,
... providedBy(self.folder) - IContainmentRoot)
>>> noLongerProvides(self.folder, IApplication)
The absolute url view is obviously not affected by virtual hosting:
...
...
lib/python/Products/Five/browser/tests/test_pages.py
View file @
17b5a358
...
...
@@ -19,47 +19,6 @@ import os, sys
if
__name__
==
'__main__'
:
execfile
(
os
.
path
.
join
(
sys
.
path
[
0
],
'framework.py'
))
def
test_ViewAcquisitionWrapping
():
"""
>>> import Products.Five.browser.tests
>>> from Products.Five import zcml
>>> zcml.load_config("configure.zcml", Products.Five)
>>> zcml.load_config('pages.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.tests.testing import simplecontent as sc
>>> sc.manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
>>> uf = self.folder.acl_users
>>> uf._doAddUser('manager', 'r00t', ['Manager'], [])
>>> self.login('manager')
>>> view = self.folder.unrestrictedTraverse('testoid/eagle.txt')
>>> view is not None
True
>>> from Products.Five.browser.tests.pages import SimpleView
>>> isinstance(view, SimpleView)
True
>>> view()
u'The eagle has landed'
This sucks, but we know it
>>> from Acquisition import aq_parent, aq_base
>>> aq_parent(view.context) is view
True
This is the right way to get the context parent
>>> view.context.aq_inner.aq_parent is not view
True
>>> view.context.aq_inner.aq_parent is self.folder
True
Clean up:
>>> from zope.app.testing.placelesssetup import tearDown
>>> tearDown()
"""
def
test_view_with_unwrapped_context
():
"""
It may be desirable when writing tests for views themselves to
...
...
@@ -118,7 +77,9 @@ def test_suite():
ZopeDocTestSuite
(),
ZopeDocFileSuite
(
'pages.txt'
,
package
=
'Products.Five.browser.tests'
),
FunctionalDocFileSuite
(
'pages_ftest.txt'
,
package
=
'Products.Five.browser.tests'
)
package
=
'Products.Five.browser.tests'
),
FunctionalDocFileSuite
(
'aqlegacy_ftest.txt'
,
package
=
'Products.Five.browser.tests'
),
))
return
suite
...
...
lib/python/Products/Five/component/__init__.py
View file @
17b5a358
...
...
@@ -36,7 +36,7 @@ def findSite(obj, iface=ISite):
"""Find a site by walking up the object hierarchy, supporting both
the ``ILocation`` API and Zope 2 Acquisition."""
while
obj
is
not
None
and
not
iface
.
providedBy
(
obj
):
obj
=
getattr
(
obj
,
'__parent__'
,
aq_parent
(
aq_inner
(
obj
)
))
obj
=
aq_parent
(
aq_inner
(
obj
))
return
obj
@
zope
.
component
.
adapter
(
zope
.
interface
.
Interface
)
...
...
lib/python/Products/Five/doc/manual.txt
View file @
17b5a358
...
...
@@ -268,13 +268,6 @@ view class are:
attribute. Typically this comes from a base class, such as
``BrowserView``.
* This also means they need to be part of the Zope 2 acquisition
system, as this is a requirement for Zope 2 security to
function. The ``BrowserView`` base class, available from
``Products.Five``, already inherits from ``Acquisition.Explicit`` to
make this be the case. Acquisition is explicit so no attributes can
be acquired by accident.
An example of a simple view::
from Products.Five import BrowserView
...
...
lib/python/Products/Five/form/objectwidget.py
View file @
17b5a358
...
...
@@ -14,31 +14,26 @@
"""Five-compatible version of ObjectWidget
This is needed because ObjectWidget uses ViewPageTemplateFile whose
macro definition is unfortunately incompatible with
ZopeTwoPageTemplateFile. So this subclass uses
ZopeTwoPageTemplateFile for the template that renders the widget's
sub-editform. Acquisition has to be mixed in to provide the
ZopeTwoPageTemplateFile with the proper acquisition context.
macro definition is unfortunately incompatible with ZopeTwoPageTemplateFile.
So this subclass uses ZopeTwoPageTemplateFile for the template that renders
the widget's sub-editform.
$Id$
"""
import
Acquisition
import
zope.app.form.browser.objectwidget
from
AccessControl
import
ClassSecurityInfo
from
Globals
import
InitializeClass
as
initializeClass
from
Products.Five.browser.pagetemplatefile
import
ZopeTwo
PageTemplateFile
from
Products.Five.browser.pagetemplatefile
import
View
PageTemplateFile
class
ObjectWidgetView
(
Acquisition
.
Explicit
,
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidgetView
):
class
ObjectWidgetView
(
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidgetView
):
security
=
ClassSecurityInfo
()
security
.
declareObjectPublic
()
template
=
ZopeTwo
PageTemplateFile
(
'objectwidget.pt'
)
template
=
View
PageTemplateFile
(
'objectwidget.pt'
)
initializeClass
(
ObjectWidgetView
)
class
ObjectWidgetClass
(
Acquisition
.
Explicit
,
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidget
):
class
ObjectWidgetClass
(
zope
.
app
.
form
.
browser
.
objectwidget
.
ObjectWidget
):
def
__init__
(
self
,
context
,
request
,
factory
,
**
kw
):
super
(
ObjectWidgetClass
,
self
).
__init__
(
context
,
request
,
factory
,
**
kw
)
...
...
@@ -58,8 +53,4 @@ class ObjectWidgetClass(Acquisition.Explicit,
val
=
self
.
context
.
schema
[
name
].
default
self
.
getSubWidget
(
name
).
setRenderedValue
(
val
)
def
ObjectWidget
(
context
,
request
,
factory
,
**
kw
):
"""Return an ObjectWidget suitable in the Five environment, with
right acquisition context"""
return
ObjectWidgetClass
(
context
,
request
,
factory
,
**
kw
).
__of__
(
context
.
context
)
ObjectWidget
=
ObjectWidgetClass
lib/python/Products/Five/formlib/formbase.py
View file @
17b5a358
...
...
@@ -18,7 +18,6 @@ $Id$
import
os.path
from
datetime
import
datetime
import
Acquisition
import
zope.event
import
zope.formlib
...
...
@@ -36,7 +35,7 @@ _PAGEFORM_PATH = os.path.join(_FORMLIB_DIR, 'pageform.pt')
_SUBPAGEFORM_PATH
=
os
.
path
.
join
(
_FORMLIB_DIR
,
'subpageform.pt'
)
class
FiveFormlibMixin
(
Acquisition
.
Explici
t
):
class
FiveFormlibMixin
(
objec
t
):
# Overrides the formlib.form.FormBase.template attributes implemented
# using NamedTemplates. NamedTemplates using ViewPageTemplateFile (like
...
...
lib/python/Products/Five/i18n.py
View file @
17b5a358
...
...
@@ -15,7 +15,7 @@
$Id$
"""
from
Acquisition
import
aq_
acquire
from
Acquisition
import
aq_
get
from
zope.interface
import
implements
from
zope.i18n.interfaces
import
IFallbackTranslationDomainFactory
from
zope.i18n.interfaces
import
ITranslationDomain
...
...
@@ -23,6 +23,7 @@ from zope.i18n.interfaces import IUserPreferredLanguages
from
zope.i18n.negotiator
import
normalize_lang
from
zope.component
import
queryUtility
from
zope.i18nmessageid
import
Message
from
zope.publisher.interfaces.browser
import
IBrowserRequest
class
FiveTranslationService
:
...
...
@@ -60,8 +61,11 @@ class FiveTranslationService:
# in Zope3, context is adapted to IUserPreferredLanguages,
# which means context should be the request in this case.
# Do not attempt to acquire REQUEST from the context, when we already
# got a request as the context
if
context
is
not
None
:
context
=
aq_acquire
(
context
,
'REQUEST'
,
None
)
if
not
IBrowserRequest
.
providedBy
(
context
):
context
=
aq_get
(
context
,
'REQUEST'
,
None
)
return
util
.
translate
(
msgid
,
mapping
=
mapping
,
context
=
context
,
target_language
=
target_language
,
default
=
default
)
...
...
lib/python/Products/Five/site/tests/test_utility.py
View file @
17b5a358
...
...
@@ -283,17 +283,17 @@ class LocalUtilityServiceTest(ZopeTestCase.ZopeTestCase):
# let's see if we can acquire something all the way from the
# root (Application) object; we need to be careful to choose
# something that's only available from the root object
from
Acquisition
import
aq_
acquire
from
Acquisition
import
aq_
get
dummy
=
zapi
.
getUtility
(
IDummyUtility
)
acquired
=
aq_
acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
acquired
=
aq_
get
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
name
,
dummy
=
zapi
.
getUtilitiesFor
(
IDummyUtility
).
next
()
acquired
=
aq_
acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
acquired
=
aq_
get
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
dummy
=
zapi
.
getAllUtilitiesRegisteredFor
(
IDummyUtility
).
next
()
acquired
=
aq_
acquire
(
dummy
,
'ZopeAttributionButton'
,
None
)
acquired
=
aq_
get
(
dummy
,
'ZopeAttributionButton'
,
None
)
self
.
failUnless
(
acquired
is
not
None
)
def
test_getNextUtility
(
self
):
...
...
lib/python/Products/Five/viewlet/README.txt
View file @
17b5a358
...
...
@@ -89,8 +89,7 @@ But now we register some viewlets for the manager
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
>>> from zope.publisher.interfaces.browser import IBrowserView
>>> from Acquisition import Explicit
>>> class WeatherBox(Explicit):
>>> class WeatherBox(object):
... zope.interface.implements(interfaces.IViewlet)
...
... def __init__(self, context, request, view, manager):
...
...
@@ -109,7 +108,7 @@ But now we register some viewlets for the manager
... IBrowserView, ILeftColumn),
... interfaces.IViewlet, name='weather')
>>> class SportBox(
Explici
t):
>>> class SportBox(
objec
t):
... zope.interface.implements(interfaces.IViewlet)
...
... def __init__(self, context, request, view, manager):
...
...
@@ -311,7 +310,7 @@ The same is true if the specified attribute does not exist:
>>> foo.render()
Traceback (most recent call last):
...
AttributeError:
bar
AttributeError:
'FooViewlet' object has no attribute 'bar'
To create simple template-based viewlets you can use the
``SimpleViewletClass()`` function. This function is very similar to its view
...
...
@@ -365,7 +364,7 @@ fully demonstrate the functionality of the base classes as well.
The viewlet will look up the resource it was given and tries to produce the
absolute URL for it:
>>> class JSResource(
Explici
t):
>>> class JSResource(
objec
t):
... def __init__(self, request):
... self.request = request
...
...
...
@@ -381,7 +380,7 @@ absolute URL for it:
The same works for the CSS resource viewlet:
>>> class CSSResource(
Explici
t):
>>> class CSSResource(
objec
t):
... def __init__(self, request):
... self.request = request
...
...
...
@@ -487,7 +486,7 @@ different item:
>>> shownColumns = []
>>> class ContentsViewletManager(
Explici
t):
>>> class ContentsViewletManager(
objec
t):
... zope.interface.implements(interfaces.IViewletManager)
... index = None
...
...
...
@@ -562,7 +561,7 @@ The Viewlets and the Final Result
Now let's create a first viewlet for the manager...
>>> class NameViewlet(
Explici
t):
>>> class NameViewlet(
objec
t):
...
... def __init__(self, context, request, view, manager):
... self.__parent__ = view
...
...
@@ -635,7 +634,7 @@ that we want to see the name as a column in the table:
Let's now write a second viewlet that will display the size of the object for
us:
>>> class SizeViewlet(
Explici
t):
>>> class SizeViewlet(
objec
t):
...
... def __init__(self, context, request, view, manager):
... self.__parent__ = view
...
...
lib/python/Products/Five/viewlet/directives.txt
View file @
17b5a358
...
...
@@ -130,8 +130,6 @@ Next let's see what happens, if we specify a template for the viewlet manager:
<Products.Five.viewlet.manager.<ViewletManager providing ILeftColumn> object ...>
>>> ILeftColumn.providedBy(manager)
True
>>> manager.template.meta_type
'Page Template (File)'
>>> manager.update()
>>> print manager.render().strip()
<div class="column">
...
...
@@ -164,8 +162,6 @@ weight attribute in the viewlet:
<class 'Products.Five.viewlet.manager.ViewletManagerBase'>)
>>> ILeftColumn.providedBy(manager)
True
>>> manager.template.meta_type
'Page Template (File)'
>>> manager.update()
>>> print manager.render().strip()
<div class="column">
...
...
lib/python/Products/Five/viewlet/manager.py
View file @
17b5a358
...
...
@@ -15,7 +15,7 @@
$Id$
"""
import
Acquisition
from
Acquisition
import
aq_base
from
AccessControl.ZopeGuards
import
guarded_hasattr
import
zope.interface
import
zope.security
...
...
@@ -24,9 +24,7 @@ from zope.viewlet.manager import ViewletManagerBase as origManagerBase
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
aq_base
=
Acquisition
.
aq_base
class
ViewletManagerBase
(
origManagerBase
,
Acquisition
.
Explicit
):
class
ViewletManagerBase
(
origManagerBase
):
"""A base class for Viewlet managers to work in Zope2"""
def
__getitem__
(
self
,
name
):
...
...
@@ -41,9 +39,6 @@ class ViewletManagerBase(origManagerBase, Acquisition.Explicit):
raise
zope
.
component
.
interfaces
.
ComponentLookupError
(
'No provider with name `%s` found.'
%
name
)
# Wrap the viewlet for security lookups
viewlet
=
viewlet
.
__of__
(
viewlet
.
context
)
# If the viewlet cannot be accessed, then raise an
# unauthorized error
if
not
guarded_hasattr
(
viewlet
,
'render'
):
...
...
@@ -65,7 +60,6 @@ class ViewletManagerBase(origManagerBase, Acquisition.Explicit):
# the object has a real context from which to determine owner
# security.
for
name
,
viewlet
in
viewlets
:
viewlet
=
viewlet
.
__of__
(
viewlet
.
context
)
if
guarded_hasattr
(
viewlet
,
'render'
):
results
.
append
((
name
,
viewlet
))
return
results
...
...
lib/python/Products/Five/viewlet/viewlet.py
View file @
17b5a358
...
...
@@ -16,19 +16,18 @@
$Id$
"""
import
os
from
Acquisition
import
Explicit
from
zope.viewlet
import
viewlet
as
orig_viewlet
import
zope.viewlet.viewlet
from
Products.Five.bbb
import
AcquisitionBBB
from
Products.Five.browser.pagetemplatefile
import
ViewPageTemplateFile
from
Products.Five.browser.pagetemplatefile
import
ZopeTwoPageTemplateFile
# We add Acquisition to all the base classes to enable security machinery
class
ViewletBase
(
orig_viewlet
.
ViewletBase
,
Explicit
):
class
ViewletBase
(
zope
.
viewlet
.
viewlet
.
ViewletBase
,
AcquisitionBBB
):
pass
class
SimpleAttributeViewlet
(
orig_viewlet
.
SimpleAttributeViewlet
,
Explicit
):
class
SimpleAttributeViewlet
(
zope
.
viewlet
.
viewlet
.
SimpleAttributeViewlet
,
AcquisitionBBB
):
pass
class
simple
(
orig_
viewlet
.
simple
):
class
simple
(
zope
.
viewlet
.
viewlet
.
simple
):
# We need to ensure that the proper __init__ is called.
__init__
=
ViewletBase
.
__init__
.
im_func
...
...
@@ -41,7 +40,7 @@ def SimpleViewletClass(template, bases=(), attributes=None,
# Create the base class hierarchy
bases
+=
(
simple
,
ViewletBase
)
attrs
=
{
'index'
:
ZopeTwo
PageTemplateFile
(
template
),
attrs
=
{
'index'
:
View
PageTemplateFile
(
template
),
'__name__'
:
name
}
if
attributes
:
attrs
.
update
(
attributes
)
...
...
@@ -52,7 +51,7 @@ def SimpleViewletClass(template, bases=(), attributes=None,
return
class_
class
ResourceViewletBase
(
orig_viewlet
.
ResourceViewletBase
,
Explicit
):
class
ResourceViewletBase
(
zope
.
viewlet
.
viewlet
.
ResourceViewletBase
):
pass
def
JavaScriptViewlet
(
path
):
...
...
@@ -61,13 +60,13 @@ def JavaScriptViewlet(path):
klass
=
type
(
'JavaScriptViewlet'
,
(
ResourceViewletBase
,
ViewletBase
),
{
'index'
:
ZopeTwo
PageTemplateFile
(
src
),
{
'index'
:
View
PageTemplateFile
(
src
),
'_path'
:
path
})
return
klass
class
CSSResourceViewletBase
(
orig_
viewlet
.
CSSResourceViewletBase
):
class
CSSResourceViewletBase
(
zope
.
viewlet
.
viewlet
.
CSSResourceViewletBase
):
pass
def
CSSViewlet
(
path
,
media
=
"all"
,
rel
=
"stylesheet"
):
...
...
@@ -76,7 +75,7 @@ def CSSViewlet(path, media="all", rel="stylesheet"):
klass
=
type
(
'CSSViewlet'
,
(
CSSResourceViewletBase
,
ViewletBase
),
{
'index'
:
ZopeTwo
PageTemplateFile
(
src
),
{
'index'
:
View
PageTemplateFile
(
src
),
'_path'
:
path
,
'_media'
:
media
,
'_rel'
:
rel
})
...
...
lib/python/Products/PageTemplates/PageTemplateFile.py
View file @
17b5a358
...
...
@@ -17,7 +17,7 @@ from logging import getLogger
import
AccessControl
from
Globals
import
package_home
,
InitializeClass
,
DevelopmentMode
from
App.config
import
getConfiguration
from
Acquisition
import
aq_parent
,
aq_inner
from
Acquisition
import
aq_parent
,
aq_inner
,
aq_get
from
ComputedAttribute
import
ComputedAttribute
from
OFS.SimpleItem
import
SimpleItem
from
OFS.Traversable
import
Traversable
...
...
@@ -87,7 +87,10 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
self
.
filename
=
filename
def
pt_getContext
(
self
):
root
=
self
.
getPhysicalRoot
()
root
=
None
meth
=
aq_get
(
self
,
'getPhysicalRoot'
,
None
)
if
meth
is
not
None
:
root
=
meth
()
context
=
self
.
_getContext
()
c
=
{
'template'
:
self
,
'here'
:
context
,
...
...
@@ -96,7 +99,7 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
'nothing'
:
None
,
'options'
:
{},
'root'
:
root
,
'request'
:
getattr
(
root
,
'REQUEST'
,
None
),
'request'
:
aq_get
(
root
,
'REQUEST'
,
None
),
'modules'
:
SecureModuleImporter
,
}
return
c
...
...
@@ -108,12 +111,11 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
kw
[
'args'
]
=
args
bound_names
[
'options'
]
=
kw
try
:
response
=
self
.
REQUEST
.
RESPONSE
request
=
aq_get
(
self
,
'REQUEST'
,
None
)
if
request
is
not
None
:
response
=
request
.
response
if
not
response
.
headers
.
has_key
(
'content-type'
):
response
.
setHeader
(
'content-type'
,
self
.
content_type
)
except
AttributeError
:
pass
# Execute the template in a new security context.
security
=
AccessControl
.
getSecurityManager
()
...
...
lib/python/Products/PageTemplates/ZopePageTemplate.py
View file @
17b5a358
...
...
@@ -17,6 +17,7 @@ $Id$
import
re
import
os
import
Acquisition
from
Acquisition
import
aq_get
from
Globals
import
ImageFile
,
package_home
,
InitializeClass
from
DateTime.DateTime
import
DateTime
from
Shared.DC.Scripts.Script
import
Script
...
...
@@ -271,7 +272,10 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
historyComparisonResults
=
html_diff
(
rev1
.
_text
,
rev2
.
_text
)
)
def
pt_getContext
(
self
,
*
args
,
**
kw
):
root
=
self
.
getPhysicalRoot
()
root
=
None
meth
=
aq_get
(
self
,
'getPhysicalRoot'
,
None
)
if
meth
is
not
None
:
root
=
meth
()
context
=
self
.
_getContext
()
c
=
{
'template'
:
self
,
'here'
:
context
,
...
...
@@ -280,7 +284,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
'nothing'
:
None
,
'options'
:
{},
'root'
:
root
,
'request'
:
getattr
(
root
,
'REQUEST'
,
None
),
'request'
:
aq_get
(
root
,
'REQUEST'
,
None
),
'modules'
:
SecureModuleImporter
,
}
return
c
...
...
@@ -302,12 +306,11 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
kw
[
'args'
]
=
args
bound_names
[
'options'
]
=
kw
try
:
response
=
self
.
REQUEST
.
RESPONSE
request
=
aq_get
(
self
,
'REQUEST'
,
None
)
if
request
is
not
None
:
response
=
request
.
response
if
not
response
.
headers
.
has_key
(
'content-type'
):
response
.
setHeader
(
'content-type'
,
self
.
content_type
)
except
AttributeError
:
pass
security
=
getSecurityManager
()
bound_names
[
'user'
]
=
security
.
getUser
()
...
...
lib/python/Shared/DC/Scripts/Bindings.py
View file @
17b5a358
...
...
@@ -20,6 +20,7 @@ from AccessControl.Permissions import view_management_screens
from
AccessControl.PermissionRole
import
_what_not_even_god_should_do
from
AccessControl.ZopeGuards
import
guarded_getattr
from
Persistence
import
Persistent
from
Acquisition
import
aq_parent
,
aq_inner
from
string
import
join
,
strip
import
re
...
...
@@ -179,6 +180,13 @@ class UnauthorizedBinding:
# Make *extra* sure that the wrapper isn't used to access
# __call__, etc.
if
name
.
startswith
(
'__'
):
# Acquisition will nowadays try to do an getattr on all
# objects which aren't Acquisition wrappers, asking for a
# __parent__ pointer. We don't want to raise Unauthorized
# in this case but simply an AttributeError.
if
name
in
(
'__parent__'
,
'__name__'
):
raise
AttributeError
(
name
)
self
.
__you_lose
()
return
guarded_getattr
(
self
.
_wrapped
,
name
,
default
)
...
...
@@ -264,11 +272,11 @@ class Bindings:
def
_getContext
(
self
):
# Utility for bindcode.
while
1
:
self
=
self
.
aq_parent
self
=
aq_parent
(
self
)
if
not
getattr
(
self
,
'_is_wrapperish'
,
None
):
parent
=
getattr
(
self
,
'aq_parent'
,
None
)
inner
=
getattr
(
self
,
'aq_inner'
,
None
)
container
=
getattr
(
inner
,
'aq_parent'
,
None
)
parent
=
aq_parent
(
self
)
inner
=
aq_inner
(
self
)
container
=
aq_parent
(
inner
)
try
:
getSecurityManager
().
validate
(
parent
,
container
,
''
,
self
)
except
Unauthorized
:
return
UnauthorizedBinding
(
'context'
,
self
)
...
...
@@ -277,11 +285,11 @@ class Bindings:
def
_getContainer
(
self
):
# Utility for bindcode.
while
1
:
self
=
self
.
aq_inner
.
aq_parent
self
=
aq_parent
(
aq_inner
(
self
))
if
not
getattr
(
self
,
'_is_wrapperish'
,
None
):
parent
=
getattr
(
self
,
'aq_parent'
,
None
)
inner
=
getattr
(
self
,
'aq_inner'
,
None
)
container
=
getattr
(
inner
,
'aq_parent'
,
None
)
parent
=
aq_parent
(
self
)
inner
=
aq_inner
(
self
)
container
=
aq_parent
(
inner
)
try
:
getSecurityManager
().
validate
(
parent
,
container
,
''
,
self
)
except
Unauthorized
:
return
UnauthorizedBinding
(
'container'
,
self
)
...
...
lib/python/ZPublisher/BaseRequest.py
View file @
17b5a358
...
...
@@ -18,6 +18,7 @@ from urllib import quote as urllib_quote
import
xmlrpc
from
zExceptions
import
Forbidden
,
Unauthorized
,
NotFound
from
Acquisition
import
aq_base
from
Acquisition.interfaces
import
IAcquirer
from
zope.interface
import
implements
,
providedBy
,
Interface
from
zope.component
import
queryMultiAdapter
...
...
@@ -95,7 +96,7 @@ class DefaultPublishTraverse(object):
request
.
response
.
setStatus
(
200
)
# We don't need to do the docstring security check
# for views, so lets skip it and return the object here.
return
subobject
.
__of__
(
object
)
return
subobject
# No view found. Reraise the error raised by __bobo_traverse__
raise
e
else
:
...
...
@@ -105,9 +106,10 @@ class DefaultPublishTraverse(object):
subobject
=
getattr
(
object
,
name
)
else
:
# We try to fall back to a view:
subobject
=
queryMultiAdapter
((
object
,
request
),
Interface
,
name
)
subobject
=
queryMultiAdapter
((
object
,
request
),
Interface
,
name
)
if
subobject
is
not
None
:
return
subobject
.
__of__
(
object
)
return
subobject
# And lastly, of there is no view, try acquired attributes, but
# only if there is no __bobo_traverse__:
...
...
@@ -312,7 +314,9 @@ class BaseRequest:
except
TraversalError
:
raise
KeyError
(
ob
,
name
)
return
ob2
.
__of__
(
ob
)
if
IAcquirer
.
providedBy
(
ob2
):
ob2
=
ob2
.
__of__
(
ob
)
return
ob2
if
name
==
'.'
:
return
ob
...
...
@@ -427,7 +431,7 @@ class BaseRequest:
else
:
# If we have reached the end of the path, we look to see
# if we can find IBrowserPublisher.browserDefault. If so,
# we call it to let the object tell us how to publish it
# we call it to let the object tell us how to publish it
.
# BrowserDefault returns the object to be published
# (usually self) and a sequence of names to traverse to
# find the method to be published.
...
...
@@ -440,7 +444,8 @@ class BaseRequest:
not
hasattr
(
object
,
'__bobo_traverse__'
)):
if
object
.
aq_parent
is
not
object
.
aq_inner
.
aq_parent
:
from
webdav.NullResource
import
NullResource
object
=
NullResource
(
parents
[
-
2
],
object
.
getId
(),
self
).
__of__
(
parents
[
-
2
])
object
=
NullResource
(
parents
[
-
2
],
object
.
getId
(),
self
).
__of__
(
parents
[
-
2
])
if
IBrowserPublisher
.
providedBy
(
object
):
adapter
=
object
...
...
@@ -451,10 +456,9 @@ class BaseRequest:
# Zope2 doesn't set up its own adapters in a lot
# of cases so we will just use a default adapter.
adapter
=
DefaultPublishTraverse
(
object
,
self
)
newobject
,
default_path
=
adapter
.
browserDefault
(
self
)
if
default_path
or
newobject
is
not
object
:
object
=
newobject
object
,
default_path
=
adapter
.
browserDefault
(
self
)
if
default_path
:
request
.
_hacked_path
=
1
if
len
(
default_path
)
>
1
:
path
=
list
(
default_path
)
...
...
lib/python/ZPublisher/HTTPRequest.py
View file @
17b5a358
...
...
@@ -1116,7 +1116,7 @@ class HTTPRequest(BaseRequest):
clone
[
'PARENTS'
]
=
[
self
[
'PARENTS'
][
-
1
]]
return
clone
def
get
_header
(
self
,
name
,
default
=
Non
e
):
def
get
Header
(
self
,
name
,
default
=
None
,
literal
=
Fals
e
):
"""Return the named HTTP header, or an optional default
argument or None if the header is not found. Note that
both original and CGI-ified header names are recognized,
...
...
@@ -1124,7 +1124,8 @@ class HTTPRequest(BaseRequest):
should all return the Content-Type header, if available.
"""
environ
=
self
.
environ
name
=
(
'_'
.
join
(
name
.
split
(
"-"
))).
upper
()
if
not
literal
:
name
=
name
.
replace
(
'-'
,
'_'
).
upper
()
val
=
environ
.
get
(
name
,
None
)
if
val
is
not
None
:
return
val
...
...
@@ -1132,6 +1133,8 @@ class HTTPRequest(BaseRequest):
name
=
'HTTP_%s'
%
name
return
environ
.
get
(
name
,
default
)
get_header
=
getHeader
# BBB
def
get
(
self
,
key
,
default
=
None
,
returnTaints
=
0
,
URLmatch
=
re
.
compile
(
'URL(PATH)?([0-9]+)$'
).
match
,
BASEmatch
=
re
.
compile
(
'BASE(PATH)?([0-9]+)$'
).
match
,
...
...
lib/python/ZPublisher/mapply.py
View file @
17b5a358
...
...
@@ -12,6 +12,7 @@
##############################################################################
"""Provide an apply-like facility that works with any mapping object
"""
import
zope.publisher.publish
def
default_call_object
(
object
,
args
,
context
):
result
=
object
(
*
args
)
# Type s<cr> to step into published object.
...
...
@@ -39,27 +40,15 @@ def mapply(object, positional=(), keyword={},
if
hasattr
(
object
,
'__bases__'
):
f
,
names
,
defaults
=
handle_class
(
object
,
context
)
else
:
f
=
object
im
=
0
if
hasattr
(
f
,
'im_func'
):
im
=
1
elif
not
hasattr
(
f
,
'func_defaults'
):
if
hasattr
(
f
,
'__call__'
):
f
=
f
.
__call__
if
hasattr
(
f
,
'im_func'
):
im
=
1
elif
not
hasattr
(
f
,
'func_defaults'
)
and
maybe
:
return
object
elif
maybe
:
return
object
if
im
:
f
=
f
.
im_func
c
=
f
.
func_code
defaults
=
f
.
func_defaults
names
=
c
.
co_varnames
[
1
:
c
.
co_argcount
]
else
:
defaults
=
f
.
func_defaults
c
=
f
.
func_code
names
=
c
.
co_varnames
[:
c
.
co_argcount
]
try
:
f
,
count
=
zope
.
publisher
.
publish
.
unwrapMethod
(
object
)
except
TypeError
:
if
maybe
:
return
object
raise
code
=
f
.
func_code
defaults
=
f
.
func_defaults
names
=
code
.
co_varnames
[
count
:
code
.
co_argcount
]
nargs
=
len
(
names
)
if
positional
:
...
...
lib/python/ZPublisher/tests/testBaseRequest.py
View file @
17b5a358
...
...
@@ -6,6 +6,7 @@ import zope.interface
import
zope.component
import
zope.testing.cleanup
import
zope.traversing.namespace
from
zope.publisher.browser
import
BrowserPage
from
zope.publisher.browser
import
IBrowserRequest
from
zope.publisher.browser
import
IDefaultBrowserLayer
from
zope.traversing.interfaces
import
ITraversable
...
...
@@ -276,9 +277,15 @@ class TestBaseRequestZope3Views(unittest.TestCase):
gsm
=
zope
.
component
.
getGlobalSiteManager
()
# Define our 'meth' view
gsm
.
registerAdapter
(
DummyView
,
(
IDummy
,
IDefaultBrowserLayer
),
None
,
'meth'
)
# Define the views
gsm
.
registerAdapter
(
DummyView
,
(
IDummy
,
IDefaultBrowserLayer
),
zope
.
interface
.
Interface
,
'meth'
)
gsm
.
registerAdapter
(
DummyPage
,
(
IDummy
,
IDefaultBrowserLayer
),
zope
.
interface
.
Interface
,
'page'
)
gsm
.
registerAdapter
(
DummyPage2
,
(
IDummy
,
IDefaultBrowserLayer
),
zope
.
interface
.
Interface
,
'page2'
)
gsm
.
registerAdapter
(
DummyPage3
,
(
IDummy
,
IDefaultBrowserLayer
),
zope
.
interface
.
Interface
,
'page3'
)
# Bind the 'view' namespace (for @@ traversal)
gsm
.
registerAdapter
(
zope
.
traversing
.
namespace
.
view
,
...
...
@@ -382,6 +389,27 @@ class TestBaseRequestZope3Views(unittest.TestCase):
r
.
traverse
(
'folder/obj/++view++meth'
)
self
.
assertEqual
(
r
[
'URL'
],
'/folder/obj/++view++meth'
)
def
test_browserDefault
(
self
):
# browserDefault can return self, () to indicate that the
# object itself wants to be published (using __call__):
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'obj'
,
DummyObjectZ3
(
'obj'
))
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder/obj/page'
)
self
.
assertEqual
(
ob
(),
'Test page'
)
# browserDefault can return another_object, () to indicate
# that that object should be published (using __call__):
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder/obj/page2'
)
self
.
assertEqual
(
ob
(),
'Test page'
)
# browserDefault can also return self.some_method, () to
# indicate that that method should be called.
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder/obj/page3'
)
self
.
assertEqual
(
ob
(),
'Test page'
)
class
DummyResponse
(
Implicit
):
...
...
@@ -512,6 +540,34 @@ class DummyView(Implicit):
def
__call__
(
self
):
return
'view on %s'
%
(
self
.
content
.
name
)
class
DummyPage
(
BrowserPage
):
# BrowserPage is an IBrowserPublisher with a browserDefault that
# returns self, () so that __call__ is invoked by the publisher.
def
__call__
(
self
):
return
'Test page'
class
DummyPage2
(
BrowserPage
):
def
browserDefault
(
self
,
request
):
# intentionally return something that's not self
return
DummyPage
(
self
.
context
,
request
),
()
# __call__ remains unimplemented, baseclass raises NotImplementedError
class
DummyPage3
(
BrowserPage
):
def
browserDefault
(
self
,
request
):
# intentionally return a method here
return
self
.
foo
,
()
def
foo
(
self
):
return
'Test page'
# __call__ remains unimplemented, baseclass raises NotImplementedError
def
test_suite
():
return
unittest
.
TestSuite
((
unittest
.
makeSuite
(
TestBaseRequest
),
...
...
@@ -519,4 +575,4 @@ def test_suite():
))
if
__name__
==
'__main__'
:
unitt
t
est
.
main
(
defaultTest
=
'test_suite'
)
unittest
.
main
(
defaultTest
=
'test_suite'
)
lib/python/ZPublisher/tests/testHTTPRequest.py
View file @
17b5a358
import
sys
import
base64
import
unittest
from
urllib
import
quote_plus
from
types
import
ListType
,
TupleType
,
StringType
,
UnicodeType
from
StringIO
import
StringIO
from
DateTime
import
DateTime
from
ZPublisher.HTTPRequest
import
HTTPRequest
,
record
,
trusted_proxies
from
ZPublisher.TaintedString
import
TaintedString
from
ZPublisher.Converters
import
type_converters
TEST_LARGEFILE_DATA
=
'''
--12345
Content-Disposition: form-data; name="file"; filename="file"
...
...
@@ -13,13 +22,10 @@ test %s
class
AuthCredentialsTests
(
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
from
ZPublisher.HTTPRequest
import
HTTPRequest
return
HTTPRequest
def
_makeOne
(
self
,
stdin
=
None
,
environ
=
None
,
response
=
None
,
clean
=
1
):
if
stdin
is
None
:
from
StringIO
import
StringIO
stdin
=
StringIO
()
if
environ
is
None
:
...
...
@@ -40,9 +46,6 @@ class AuthCredentialsTests( unittest.TestCase ):
return
self
.
_getTargetClass
()(
stdin
,
environ
,
response
,
clean
)
def
test__authUserPW_simple
(
self
):
import
base64
user_id
=
'user'
password
=
'password'
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
...
...
@@ -57,11 +60,7 @@ class AuthCredentialsTests( unittest.TestCase ):
self
.
assertEqual
(
password_x
,
password
)
def
test__authUserPW_with_embedded_colon
(
self
):
# http://www.zope.org/Collectors/Zope/2039
import
base64
user_id
=
'user'
password
=
'embedded:colon'
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
...
...
@@ -75,43 +74,20 @@ class AuthCredentialsTests( unittest.TestCase ):
self
.
assertEqual
(
user_id_x
,
user_id
)
self
.
assertEqual
(
password_x
,
password
)
class
RecordTests
(
unittest
.
TestCase
):
def
test_repr
(
self
):
from
ZPublisher.HTTPRequest
import
record
record
=
record
()
record
.
a
=
1
record
.
b
=
'foo'
r
=
repr
(
record
)
d
=
eval
(
r
)
self
.
assertEqual
(
d
,
record
.
__dict__
)
def
test_contains
(
self
):
from
ZPublisher.HTTPRequest
import
record
record
=
record
()
record
.
a
=
1
self
.
assertTrue
(
'a'
in
record
)
def
test_iter
(
self
):
from
ZPublisher.HTTPRequest
import
record
record
=
record
()
record
.
a
=
1
record
.
b
=
2
record
.
c
=
3
for
k
in
record
:
self
.
assertTrue
(
k
in
(
'a'
,
'b'
,
'c'
))
def
test_len
(
self
):
from
ZPublisher.HTTPRequest
import
record
record
=
record
()
record
.
a
=
1
record
.
b
=
2
record
.
c
=
3
self
.
assertEqual
(
len
(
record
),
3
)
class
RecordTests
(
unittest
.
TestCase
):
def
test_repr
(
self
):
rec
=
record
()
rec
.
a
=
1
rec
.
b
=
'foo'
r
=
repr
(
rec
)
d
=
eval
(
r
)
self
.
assertEqual
(
d
,
rec
.
__dict__
)
class
ProcessInputsTests
(
unittest
.
TestCase
):
def
_getHTTPRequest
(
self
,
env
):
from
ZPublisher.HTTPRequest
import
HTTPRequest
return
HTTPRequest
(
None
,
env
,
None
)
def
_processInputs
(
self
,
inputs
):
...
...
@@ -141,9 +117,6 @@ class ProcessInputsTests(unittest.TestCase):
# when one is found.
# Also raises an Assertion if a string which *should* have been
# tainted is found, or when a tainted string is not deemed dangerous.
from
types
import
ListType
,
TupleType
,
StringType
,
UnicodeType
from
ZPublisher.HTTPRequest
import
record
from
ZPublisher.TaintedString
import
TaintedString
retval
=
0
...
...
@@ -221,8 +194,6 @@ class ProcessInputsTests(unittest.TestCase):
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
def
testSimpleMarshalling
(
self
):
from
DateTime
import
DateTime
inputs
=
(
(
'num:int'
,
'42'
),
(
'fract:float'
,
'4.2'
),
(
'bign:long'
,
'45'
),
(
'words:string'
,
'Some words'
),
(
'2tokens:tokens'
,
'one two'
),
...
...
@@ -476,9 +447,6 @@ class ProcessInputsTests(unittest.TestCase):
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
def
testSimpleContainersWithTaints
(
self
):
from
types
import
ListType
,
TupleType
from
ZPublisher.HTTPRequest
import
record
inputs
=
(
(
'toneitem:list'
,
'<one>'
),
(
'<tkeyoneitem>:list'
,
'one'
),
...
...
@@ -633,8 +601,6 @@ class ProcessInputsTests(unittest.TestCase):
def
testNoTaintedExceptions
(
self
):
# Feed tainted garbage to the conversion methods, and any exception
# returned should be HTML safe
from
ZPublisher.Converters
import
type_converters
from
DateTime
import
DateTime
for
type
,
convert
in
type_converters
.
items
():
try
:
convert
(
'<html garbage>'
)
...
...
@@ -717,12 +683,10 @@ class RequestTests( unittest.TestCase ):
def
testRemoveStdinReferences
(
self
):
# Verifies that all references to the input stream go away on
# request.close(). Otherwise a tempfile may stick around.
import
sys
from
StringIO
import
StringIO
s
=
StringIO
(
TEST_FILE_DATA
)
env
=
TEST_ENVIRON
.
copy
()
start_count
=
sys
.
getrefcount
(
s
)
from
ZPublisher.HTTPRequest
import
HTTPRequest
req
=
HTTPRequest
(
s
,
env
,
None
)
req
.
processInputs
()
self
.
assertNotEqual
(
start_count
,
sys
.
getrefcount
(
s
))
# Precondition
...
...
@@ -731,10 +695,9 @@ class RequestTests( unittest.TestCase ):
def
testFileName
(
self
):
# checks fileupload object supports the filename
from
StringIO
import
StringIO
s
=
StringIO
(
TEST_LARGEFILE_DATA
)
env
=
TEST_ENVIRON
.
copy
()
from
ZPublisher.HTTPRequest
import
HTTPRequest
req
=
HTTPRequest
(
s
,
env
,
None
)
req
.
processInputs
()
f
=
req
.
form
.
get
(
'file'
)
...
...
@@ -743,11 +706,9 @@ class RequestTests( unittest.TestCase ):
def
testFileIterator
(
self
):
# checks fileupload object supports the iterator protocol
# collector entry 1837
import
sys
from
StringIO
import
StringIO
s
=
StringIO
(
TEST_FILE_DATA
)
env
=
TEST_ENVIRON
.
copy
()
from
ZPublisher.HTTPRequest
import
HTTPRequest
req
=
HTTPRequest
(
s
,
env
,
None
)
req
.
processInputs
()
f
=
req
.
form
.
get
(
'file'
)
...
...
@@ -763,8 +724,6 @@ class RequestTests( unittest.TestCase ):
'SERVER_NAME'
:
'localhost'
,
'SERVER_PORT'
:
'80'
,
}
from
StringIO
import
StringIO
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
zope.publisher.base
import
DebugFlags
s
=
StringIO
(
''
)
...
...
@@ -881,8 +840,6 @@ class RequestTests( unittest.TestCase ):
'SERVER_NAME'
:
'localhost'
,
'SERVER_PORT'
:
'80'
,
}
from
StringIO
import
StringIO
from
ZPublisher.HTTPRequest
import
HTTPRequest
s
=
StringIO
(
''
)
env
=
TEST_ENVIRON
.
copy
()
...
...
@@ -902,8 +859,6 @@ class RequestTests( unittest.TestCase ):
'REMOTE_ADDR'
:
'127.0.0.1'
,
'HTTP_X_FORWARDED_FOR'
:
'10.1.20.30, 192.168.1.100'
,
}
from
StringIO
import
StringIO
from
ZPublisher.HTTPRequest
import
HTTPRequest
,
trusted_proxies
s
=
StringIO
(
''
)
env
=
TEST_ENVIRON
.
copy
()
...
...
@@ -925,6 +880,29 @@ class RequestTests( unittest.TestCase ):
request
=
HTTPRequest
(
s
,
env
,
None
)
self
.
assertEqual
(
request
.
getClientAddr
(),
''
)
def
testGetHeader
(
self
):
s
=
StringIO
(
''
)
env
=
TEST_ENVIRON
.
copy
()
request
=
HTTPRequest
(
s
,
env
,
None
)
self
.
assertEqual
(
request
.
getHeader
(
'Content-Type'
),
'multipart/form-data; boundary=12345'
)
# getHeader is agnostic of case
self
.
assertEqual
(
request
.
getHeader
(
'content-type'
),
'multipart/form-data; boundary=12345'
)
# and of dashes vs. underscores
self
.
assertEqual
(
request
.
getHeader
(
'content_type'
),
'multipart/form-data; boundary=12345'
)
# the 'literal' argument can turn this normalization off:
self
.
assertEqual
(
request
.
getHeader
(
'Content-Type'
,
literal
=
True
),
None
)
# the 'default' argument can be used to get something other than
# None when the lookup fails:
self
.
assertEqual
(
request
.
getHeader
(
'Not-existant'
,
default
=
'Whatever'
),
'Whatever'
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
...
...
lib/python/ZPublisher/tests/test_mapply.py
0 → 100644
View file @
17b5a358
##############################################################################
#
# Copyright (c) 2007 Zope Corporation 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.
#
##############################################################################
"""Test mapply() function
"""
import
unittest
import
ExtensionClass
import
Acquisition
from
ZPublisher.mapply
import
mapply
class
MapplyTests
(
unittest
.
TestCase
):
def
testMethod
(
self
):
def
compute
(
a
,
b
,
c
=
4
):
return
'%d%d%d'
%
(
a
,
b
,
c
)
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
v
=
mapply
(
compute
,
(),
values
)
self
.
failUnlessEqual
(
v
,
'235'
)
v
=
mapply
(
compute
,
(
7
,),
values
)
self
.
failUnlessEqual
(
v
,
'735'
)
def
testClass
(
self
):
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
class
c
(
object
):
a
=
3
def
__call__
(
self
,
b
,
c
=
4
):
return
'%d%d%d'
%
(
self
.
a
,
b
,
c
)
compute
=
__call__
cc
=
c
()
v
=
mapply
(
cc
,
(),
values
)
self
.
failUnlessEqual
(
v
,
'335'
)
del
values
[
'c'
]
v
=
mapply
(
cc
.
compute
,
(),
values
)
self
.
failUnlessEqual
(
v
,
'334'
)
class
c2
:
"""Must be a classic class."""
c2inst
=
c2
()
c2inst
.
__call__
=
cc
v
=
mapply
(
c2inst
,
(),
values
)
self
.
failUnlessEqual
(
v
,
'334'
)
def
testObjectWithCall
(
self
):
# Make sure that the __call__ of an object can also be another
# callable object. mapply will do the right thing and
# recursive look for __call__ attributes until it finds an
# actual method:
class
CallableObject
:
def
__call__
(
self
,
a
,
b
):
return
'%s%s'
%
(
a
,
b
)
class
Container
:
__call__
=
CallableObject
()
v
=
mapply
(
Container
(),
(
8
,
3
),
{})
self
.
assertEqual
(
v
,
'83'
)
def
testUncallableObject
(
self
):
# Normally, mapply will raise a TypeError if it encounters an
# uncallable object (e.g. an interger ;))
self
.
assertRaises
(
TypeError
,
mapply
,
2
,
(),
{})
# Unless you enable the 'maybe' flag, in which case it will
# only maybe call the object
self
.
assertEqual
(
mapply
(
2
,
(),
{},
maybe
=
True
),
2
)
def
testNoCallButAcquisition
(
self
):
# Make sure that mapply won't erroneously walk up the
# Acquisition chain when looking for __call__ attributes:
class
Root
(
ExtensionClass
.
Base
):
def
__call__
(
self
):
return
'The root __call__'
class
NoCallButAcquisition
(
Acquisition
.
Implicit
):
pass
ob
=
NoCallButAcquisition
().
__of__
(
Root
())
self
.
assertRaises
(
TypeError
,
mapply
,
ob
,
(),
{})
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
MapplyTests
))
return
suite
lib/python/Zope2/App/startup.py
View file @
17b5a358
...
...
@@ -18,6 +18,9 @@ from AccessControl.SecurityManagement import getSecurityManager
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_base
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_parent
from
App.config
import
getConfiguration
from
time
import
asctime
from
types
import
StringType
,
ListType
...
...
@@ -130,7 +133,7 @@ def validated_hook(request, user):
newSecurityManager
(
request
,
user
)
version
=
request
.
get
(
Globals
.
VersionNameName
,
''
)
if
version
:
object
=
user
.
aq_parent
object
=
aq_parent
(
user
)
if
not
getSecurityManager
().
checkPermission
(
'Join/leave Versions'
,
object
):
request
[
'RESPONSE'
].
setCookie
(
...
...
@@ -231,7 +234,7 @@ class ZPublisherExceptionHook:
while
1
:
f
=
getattr
(
published
,
self
.
raise_error_message
,
None
)
if
f
is
None
:
published
=
getattr
(
published
,
'aq_parent'
,
None
)
published
=
aq_parent
(
published
)
if
published
is
None
:
raise
t
,
v
,
traceback
else
:
...
...
@@ -241,8 +244,10 @@ class ZPublisherExceptionHook:
while
1
:
if
getattr
(
client
,
self
.
error_message
,
None
)
is
not
None
:
break
client
=
getattr
(
client
,
'aq_parent'
,
None
)
if
client
is
None
:
client
=
aq_parent
(
client
)
# If we are going in circles without getting the error_message
# just raise
if
client
is
None
or
aq_base
(
client
)
is
aq_base
(
published
):
raise
t
,
v
,
traceback
if
REQUEST
.
get
(
'AUTHENTICATED_USER'
,
None
)
is
None
:
...
...
@@ -296,8 +301,7 @@ class TransactionsManager:
object
=
None
break
to_append
=
(
object
.
__name__
,)
+
to_append
object
=
getattr
(
object
,
'aq_inner'
,
object
)
object
=
getattr
(
object
,
'aq_parent'
,
None
)
object
=
aq_parent
(
aq_inner
(
object
))
if
object
is
not
None
:
path
=
'/'
.
join
(
object
.
getPhysicalPath
()
+
to_append
)
...
...
@@ -312,11 +316,8 @@ class TransactionsManager:
T
.
note
(
path
)
auth_user
=
request_get
(
'AUTHENTICATED_USER'
,
None
)
if
auth_user
is
not
None
:
try
:
auth_folder
=
auth_user
.
aq_parent
except
AttributeError
:
# Most likely some product forgot to call __of__()
# on the user object.
auth_folder
=
aq_parent
(
auth_user
)
if
auth_folder
is
None
:
ac_logger
.
warning
(
'A user object of type %s has no aq_parent.'
,
type
(
auth_user
)
...
...
@@ -326,6 +327,3 @@ class TransactionsManager:
auth_path
=
'/'
.
join
(
auth_folder
.
getPhysicalPath
()[
1
:
-
1
])
T
.
setUser
(
auth_user
.
getId
(),
auth_path
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment