Skip to content

Commit

Permalink
Merge branch 'master' into roadmap
Browse files Browse the repository at this point in the history
  • Loading branch information
dataflake committed Jun 18, 2020
2 parents 3c820d5 + 3fb6f3d commit 7fd8ef3
Show file tree
Hide file tree
Showing 17 changed files with 262 additions and 43 deletions.
9 changes: 9 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
5.0a3 (unreleased)
------------------

- Fix ``default`` keyword handling in page templates
(`#846 <https://github.com/zopefoundation/Zope/issues/846>`_)

- Fix parsing of package version and show correct major version in the ZMI

- Improve solidity of the ``debugError`` method.
(`#829 <https://github.com/zopefoundation/Zope/issues/829>`_)

- Use ``Chameleon`` (>= 3.7.2) configuration to get better
information for errors detected during template execution
(`#837 <https://github.com/zopefoundation/Zope/issues/837>`_).


5.0a2 (2020-04-24)
------------------
Expand Down
4 changes: 2 additions & 2 deletions constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ AccessControl==4.2
Acquisition==4.6
AuthEncoding==4.1
BTrees==4.7.2
Chameleon==3.7.0
Chameleon==3.7.2
DateTime==4.3
DocumentTemplate==3.2.2
DocumentTemplate==3.2.3
ExtensionClass==4.4
Missing==4.1
MultiMapping==4.1
Expand Down
Binary file modified docs/zopebook/Figures/zoo1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 27 additions & 22 deletions docs/zopebook/SimpleExamples.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
Creating Basic Zope Applications
================================

.. include:: includes/zope2_notice.rst

.. todo:
- add new screen shots
.. note::

In order to create objects of type `Script (Python)` make sure to also
install the package ``Products.PythonScripts``.


This chapter will take you, step by step, through building a basic web
application in Zope. As we go through the chapter, we will examine some of
Zope's main concepts at work. Using Zope *Folder*, *Script (Python)*, and
Expand Down Expand Up @@ -70,15 +74,14 @@ familiar with the ZMI, refer to the `Installing and Starting Zope

1. Navigate to Zope's top-level *root* folder.

2. Use the *Add* list to create a new *Folder*.
2. Use the *Select type to add* dropdown to create a new *Folder*. (We will
refer to this dropdown as "*Add* list" from here on out)

3. Give the new folder the *Id* 'ZopeZoo'.

4. Check *Create public interface*.

5. Click *Add*.
4. Click *Add*.

(For now, we will ignore the optional *Title* fields.)
(For now, we will ignore the optional *Title* field.)

Designing a Navigable Zoo
-------------------------
Expand Down Expand Up @@ -113,9 +116,10 @@ Step 2: Create Site Organization
'Lizards' and 'Snakes'.

In Zope's Navigator frame on the left side, you should see an icon for the
*ZopeZoo* folder. (If you don't see it, click *Refresh* in the Navigator).
*ZopeZoo* folder. (If you don't see it, click on the cogwheel icon and then
click *Refresh* in the Navigator).
To view the *ZopeZoo* folder hierarchy - i.e. our nascent web site's
structure - expand the *ZopeZoo* folder by clicking the little plus sign
structure - expand the *ZopeZoo* folder by clicking the little triangle
next to the icon. Similarly expand the zoo subfolders. You'll see
something like the figure below.

Expand Down Expand Up @@ -174,9 +178,15 @@ Step 3: Create the Style Sheet
At this stage, the HTML page the web designer created for us is valid XHTML
1.0 Strict and could also live in a static *File* object. But in the next
steps we will convert the page into a dynamic template by adding TAL and
METAL statements, so we need a *Page Template* object. For now we use the
*index_html* method already added by selecting *Create public interface* in
step 1.
METAL statements, so we need a *Page Template* object:

1. Go back to the top level of our zoo website, the *ZopeZoo* folder.

2. Select *Page Template* from the *Add* list.

3. Give the Page Template an *Id* of 'index_html'.

4. Click *Add*.

Step 4: Create the Main Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -185,8 +195,7 @@ Step 4: Create the Main Template

2. Replace all of the stock template code with this::

<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<!DOCTYPE html>
<html>
<head>

Expand Down Expand Up @@ -362,8 +371,7 @@ Step 10: Factor out Basic Look and Feel
all these changes our main template - now called *z_zoo.pt* - looks
like this::

<metal:macro metal:define-macro="page"><!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<metal:macro metal:define-macro="page"><!DOCTYPE html>
<html>
<head>

Expand Down Expand Up @@ -530,16 +538,13 @@ Step 14: Adding *index_html* Script and Template
1. Within the *Files* folder, add this new *Script (Python)* with the
*Id* 'index_html'::

## Script (Python) "index_html"
##parameters=
##
library_items = []
items = context.objectValues(['File'])
for item in items:
library_items.append(
{ 'title': item.title_or_id(),
'url': item.absolute_url(),
'modified': item.bobobase_modification_time().aCommon()
'modified': container.last_modified(item),
} )

options = { 'library_items': tuple(library_items) }
Expand Down Expand Up @@ -653,15 +658,15 @@ Step 16: Making the Library Sortable
sort_title_url = ''
sort_modified_url = '%s?sort=modified' % context.absolute_url()
else:
sort_on = ( ('bobobase_modification_time', 'cmp', 'desc'), )
sort_on = ( ('_p_mtime', 'cmp', 'desc'), )
sort_title_url = '%s?sort=title' % context.absolute_url()
sort_modified_url = ''
items = sequence.sort(items, sort_on)
for item in items:
library_items.append(
{ 'title': item.title_or_id(),
'url': item.absolute_url(),
'modified': item.bobobase_modification_time().aCommon()
'modified': container.last_modified(item),
} )

options = { 'sort_title_url': sort_title_url,
Expand Down
4 changes: 2 additions & 2 deletions requirements-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ AccessControl==4.2
Acquisition==4.6
AuthEncoding==4.1
BTrees==4.7.2
Chameleon==3.7.0
Chameleon==3.7.2
DateTime==4.3
DocumentTemplate==3.2.2
DocumentTemplate==3.2.3
ExtensionClass==4.4
Missing==4.1
MultiMapping==4.1
Expand Down
2 changes: 1 addition & 1 deletion src/App/dtml/cpContents.dtml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<table class="table">
<tr>
<th class="text-muted">Zope Version</th>
<td class="code">&dtml-version_txt;</td>
<td class="code">&dtml-ZopeVersion;</td>
</tr>
<tr>
<th class="text-muted">Python Version</th>
Expand Down
2 changes: 1 addition & 1 deletion src/App/dtml/manage_navbar.dtml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</div>
<a class="navbar-brand" title="To Zope Root"
href="<dtml-var "REQUEST.getVirtualRoot()">/manage" target="_parent">
<span class="product">ZOPE 4</span>
<span class="product">ZOPE <dtml-var "ZopeVersion(major=1)"></span>
</a>
<ul class="navbar-nav flex-row ml-sm-auto d-flex">

Expand Down
68 changes: 67 additions & 1 deletion src/App/tests/test_getZopeVersion.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,72 @@ def test_major(self):

def test_types(self):
zv = getZopeVersion()
for i in (0, 1, 2, 4):
for i in (0, 1, 4):
self.assertIsInstance(zv[i], int, str(i))
self.assertIsInstance(zv[3], str, '3')

def test__parse_version_data(self):
from App.version_txt import _parse_version_data

parsed = _parse_version_data('5')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 0)
self.assertEqual(parsed.micro, 0)
self.assertEqual(parsed.status, '')
self.assertEqual(parsed.release, -1)

parsed = _parse_version_data('5a2')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 0)
self.assertEqual(parsed.micro, '0a2')
self.assertEqual(parsed.status, '')
self.assertEqual(parsed.release, -1)

parsed = _parse_version_data('5a2.dev0')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 0)
self.assertEqual(parsed.micro, '0a2')
self.assertEqual(parsed.status, 'dev')
self.assertEqual(parsed.release, 0)

parsed = _parse_version_data('5.dev0')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 0)
self.assertEqual(parsed.micro, 0)
self.assertEqual(parsed.status, 'dev')
self.assertEqual(parsed.release, 0)

parsed = _parse_version_data('5.1')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 1)
self.assertEqual(parsed.micro, 0)
self.assertEqual(parsed.status, '')
self.assertEqual(parsed.release, -1)

parsed = _parse_version_data('5.1a2.dev0')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 1)
self.assertEqual(parsed.micro, '0a2')
self.assertEqual(parsed.status, 'dev')
self.assertEqual(parsed.release, 0)

parsed = _parse_version_data('5.1.2')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 1)
self.assertEqual(parsed.micro, 2)
self.assertEqual(parsed.status, '')
self.assertEqual(parsed.release, -1)

parsed = _parse_version_data('5.1.3.dev0')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 1)
self.assertEqual(parsed.micro, 3)
self.assertEqual(parsed.status, 'dev')
self.assertEqual(parsed.release, 0)

parsed = _parse_version_data('5.1.3a1.dev0')
self.assertEqual(parsed.major, 5)
self.assertEqual(parsed.minor, 1)
self.assertEqual(parsed.micro, '3a1')
self.assertEqual(parsed.status, 'dev')
self.assertEqual(parsed.release, 0)
57 changes: 47 additions & 10 deletions src/App/version_txt.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,36 @@
ZopeVersion = collections.namedtuple(
"ZopeVersion",
["major", "minor", "micro", "status", "release"])
VERSION_PATTERN = r"""
v?
(?:
(?:(?P<epoch>[0-9]+)!)? # epoch
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
(?P<pre> # pre-release
[-_\.]?
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
[-_\.]?
(?P<pre_n>[0-9]+)?
)?
(?P<post> # post release
(?:-(?P<post_n1>[0-9]+))
|
(?:
[-_\.]?
(?P<post_l>post|rev|r)
[-_\.]?
(?P<post_n2>[0-9]+)?
)
)?
(?P<dev> # dev release
[-_\.]?
(?P<dev_l>dev)
[-_\.]?
(?P<dev_n>[0-9]+)?
)?
)
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""


def _prep_version_data():
Expand All @@ -32,17 +62,24 @@ def _prep_version_data():
pyver = "python %d.%d.%d, %s" % (v[0], v[1], v[2], sys.platform)
dist = pkg_resources.get_distribution('Zope')
_version_string = "%s, %s" % (dist.version, pyver)
_zope_version = _parse_version_data(dist.version)

expr = re.compile(
r'(?P<major>[0-9]+)\.(?P<minor>[0-9]+)(\.(?P<micro>[0-9]+))?'
'(?P<status>[A-Za-z]+)?(?P<release>[0-9]+)?')
version_dict = expr.match(dist.version).groupdict()
_zope_version = ZopeVersion(
int(version_dict.get('major') or -1),
int(version_dict.get('minor') or -1),
int(version_dict.get('micro') or -1),
version_dict.get('status') or '',
int(version_dict.get('release') or -1))

def _parse_version_data(version_string):
expr = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$",
re.VERBOSE | re.IGNORECASE)
version_dict = expr.match(version_string).groupdict()
rel = tuple(int(i) for i in version_dict['release'].split('.'))
micro = rel[2] if len(rel) >= 3 else 0
if version_dict['pre']:
micro = '%s%s' % (micro, version_dict['pre'])

return ZopeVersion(
rel[0] if len(rel) >= 1 else 0,
rel[1] if len(rel) >= 2 else 0,
micro,
version_dict.get('dev_l') or '',
int(version_dict.get('dev_n') or -1))


def version_txt():
Expand Down
20 changes: 20 additions & 0 deletions src/OFS/Application.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
from AccessControl import ClassSecurityInfo
from AccessControl.class_init import InitializeClass
from AccessControl.Permission import ApplicationDefaultPermissions
from AccessControl.Permissions import view_management_screens
from Acquisition import aq_base
from App import FactoryDispatcher
from App.ApplicationManager import ApplicationManager
from App.ProductContext import ProductContext
from App.version_txt import getZopeVersion
from DateTime import DateTime
from OFS.FindSupport import FindSupport
from OFS.metaconfigure import get_packages_to_initialize
Expand Down Expand Up @@ -137,6 +139,24 @@ def ZopeTime(self, *args):
"""Utility function to return current date/time"""
return DateTime(*args)

@security.protected(view_management_screens)
def ZopeVersion(self, major=False):
"""Utility method to return the Zope version
Restricted to ZMI to prevent information disclosure
"""
zversion = getZopeVersion()
if major:
return zversion.major
else:
version = '%s.%s.%s' % (zversion.major,
zversion.minor,
zversion.micro)
if zversion.status:
version += '.%s%s' % (zversion.status, zversion.release)

return version

def DELETE(self, REQUEST, RESPONSE):
"""Delete a resource object."""
self.dav__init(REQUEST, RESPONSE)
Expand Down
12 changes: 12 additions & 0 deletions src/OFS/tests/testApplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ def test_redirect_regression(self):
RedirectException,
method, 'http://google.nl', 'http://other.url')

def test_ZopeVersion(self):
import pkg_resources
from App.version_txt import getZopeVersion

app = self._makeOne()
pkg_version = pkg_resources.get_distribution('Zope').version
zversion = getZopeVersion()

self.assertEqual(app.ZopeVersion(major=True), zversion.major)
self.assertEqual(app.ZopeVersion(major=True),
int(pkg_version.split('.')[0]))


class ApplicationPublishTests(FunctionalTestCase):

Expand Down
Loading

0 comments on commit 7fd8ef3

Please sign in to comment.