Merge pull request #142 from plone/english-fixes

English fixes
This commit is contained in:
Nejc Zupan 2013-10-09 17:16:04 -07:00
commit 78fb7b01c8
20 changed files with 250 additions and 172 deletions

View File

@ -21,24 +21,24 @@ plone.api
* `Continuous Integration @ Travis CI <http://travis-ci.org/plone/plone.api>`_
* `Code Coverage @ Coveralls.io <http://coveralls.io/r/plone/plone.api>`_
The intention of this package is to be transitional. It points out the parts of
Plone which are particularly nasty -- we hope they will get fixed so that we
can deprecate the ``plone.api`` methods that cover them up, but the
documentation can still be useful.
The intention of this package is to provide clear API methods for Plone
functionality which may be confusing or difficult to access. As the underlying
code improves some API methods may be deprecated and the documentation here
will be updated to show how to use the improved code (even if it means not
using ``plone.api``)
Some parts of the documentation already are this way: they don't use
``plone.api`` methods directly, but simply provide guidance on achieving a task
using Plone's internals. Example: usage of the catalog in `Find content`
example.
Some parts of the documentation do not use *plone.api* methods directly, but
simply provide guidance on achieving a task using Plone's internal API. For
example, using the portal catalog (see 'Find content objects').
The intention is to cover 20% of the tasks we do 80% of the time. Keeping
everything in one place helps keep the API introspectable and discoverable,
which are important aspects of being Pythonic.
The intention is to cover 20% of the tasks any Plone developer does 80% of the
time. By keeping everything in one place, the API stays introspectable and
discoverable, important aspects of being Pythonic.
.. note::
This package is still under development, but should be fairly stable and is
already being used in production. It's currently a release candidate,
meaning that we don't intend to change method signatures, but it may still
happen.
This package is stable and used in production, but from time to time
changes will be made to the API. Additional api methods may be introduced
in minor versions (1.1 -> 1.2). Backward-incompatible changes to the API
will be restricted to major versions (1.x -> 2.x).

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/about.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/about.html>`_
so you have working references and proper formatting.
=====
@ -15,14 +15,14 @@ Inspiration
We want `plone.api` to be developed with `PEP 20
<http://www.python.org/dev/peps/pep-0020/>`_ idioms in mind, in particular:
| Explicit is better than implicit.
| Readability counts.
| There should be one -- and preferably only one -- obvious way to do it.
| Now is better than never.
| If the implementation is hard to explain, it's a bad idea.
| If the implementation is easy to explain, it may be a good idea.
| Explicit is better than implicit.
| Readability counts.
| There should be one-- and preferably only one --obvious way to do it.
| Now is better than never.
| If the implementation is hard to explain, it's a bad idea.
| If the implementation is easy to explain, it may be a good idea.
All contributions to :mod:`plone.api` should keep these important rules in mind.
All contributions to `plone.api` should keep these rules in mind.
Two libraries are especially inspiring:
@ -32,21 +32,18 @@ Two libraries are especially inspiring:
designed, is consistent, explicit, and easy to learn.
`Requests <http://docs.python-requests.org>`_
As of this writing, this is still a very new library, but just looking at
`a comparison between the urllib2 way and the requests way
<https://gist.github.com/973705>`_, as well as the rest of its documentation,
one cannot but see a parallel between the way we *have been* and the way we
*should be* writing code for Plone (or at least have that option).
If you look at the documentation for this library, or make `a comparison
between the urllib2 way and the requests way
<https://gist.github.com/973705>`_, you cannot but see a parallel between
the way we *have been* and the way we *should be* writing code for Plone. At
the least, we should have the option to write such clean code.
The API provides grouped functional access to otherwise dispersed logic
in Plone. Plone's original distribution of logic is a result of two things:
the historic re-use of CMF- and Zope-methods and reasonable, but
at first hard to understand splits like ``acl_users.*`` and
``portal_memberdata``.
That's why we've created a set of useful methods that implement best-practice
access to the original dispersed APIs. In this way we also document in code
how to use Plone directly.
The API provides grouped functional access to otherwise distributed logic in
Plone. This distribution is a result of two historical factors: re-use of CMF-
and Zope-methods and reasonable but hard to remember splits like `acl_users`
and `portal_memberdata`. Methods defined in `plone.api` implement
best-practice access to the original distributed APIs. These methods also
provide clear documentation of how best to access Plone APIs directly.
.. note::
If you doubt those last sentences: We had five different ways to get the
@ -54,12 +51,11 @@ how to use Plone directly.
an object. With this in mind, it's obvious that even the most simple
tasks can't be documented in Plone in a sane way.
Also, we don't intend to cover all possible use-cases. Only the most common
ones. If you need to do something that :mod:`plone.api` does not support,
just use the underlying APIs directly. We will cover 20% of tasks that are
being done 80% of the time, and not one more. We try to document sensible use
cases even when we don't provide them, though.
We do not intend to cover all possible use-cases, only the most common. We
will cover the 20% of possible tasks on which we spend 80% of our time. If you
need to do something that `plone.api` does not support, use the underlying
APIs directly. We try to document sensible use cases even when we don't
provide APIs for them, though.
Design decisions
================
@ -67,10 +63,10 @@ Design decisions
Import and usage style
----------------------
API methods are grouped by their field of usage. For example:
:ref:`chapter_portal`, :ref:`chapter_content`, :ref:`chapter_users`
and :ref:`chapter_groups`. Hence the importing and usage of API
methods look like this:
API methods are grouped according to what they affect. For example:
:ref:`chapter_portal`, :ref:`chapter_content`, :ref:`chapter_users`,
:ref:`chapter_env` and :ref:`chapter_groups`. In general, importing and using
an API looks something like this:
.. invisible-code-block: python
@ -92,31 +88,31 @@ methods look like this:
self.assertEqual(catalog.__class__.__name__, 'CatalogTool')
self.assertEqual(user.__class__.__name__, 'MemberData')
In other words, always import the top-level package (``from plone import api``)
Always import the top-level package (``from plone import api``)
and then use the group namespace to access the method you want
(``portal = api.portal.get()``).
All example code should adhere to this style, so we encourage one and only
one preferred way of consuming API methods.
All example code should adhere to this style, to encourage one and only one
preferred way of consuming API methods.
Prefer keyword arguments
------------------------
For the following reasons the example code in the API (and hence the
recommendation to people on how to use it) shall always prefer using keyword
instead of positional arguments:
We prefer using keyword arguments to positional arguments. Example code in
`plone.api` will use this style, and we recommend users to follow this
convention. For the curious, here are the reasons:
#. There will never be a doubt when writing a method on whether an argument
should be positional or not. Decision already made.
#. There will never be a doubt when using the API on which argument comes
first, or which ones are named/positional. All arguments are named.
#. When using positional arguments, the method signature is dictated by the
underlying implementation. Think required vs. optional arguments. Named
arguments are always optional in Python. This allows us to change
implementation details and leave the signature unchanged. In other words,
the underlying API code can change substantially and the code using it will
remain valid.
underlying implementation (think required vs. optional arguments). Named
arguments are always optional in Python. Using keywords allows
implementation details to change while the signature is preserved. In other
words, the underlying API code can change substantially but code using it
will remain valid.
#. The arguments can all be passed as a dictionary.
@ -124,13 +120,11 @@ instead of positional arguments:
# GOOD
from plone import api
portal = api.portal.get()
alice = api.user.get(username='alice@plone.org')
# BAD
from plone.api import portal, user
portal = portal.get()
alie = user.get('alice@plone.org')
from plone.api import user
alice = user.get('alice@plone.org')
FAQ
@ -142,15 +136,14 @@ Why aren't we using wrappers?
We could wrap an object (like a user) with an API to make it more usable
right now. That would be an alternative to the convenience methods.
But telling developers that they will get yet another object from the API which
isn't the requested object, but an API-wrapped one instead, would be very hard.
Also, making this wrap transparent in order to make the returned object
directly usable would be nearly impossible, because we'd have to proxy all the
:mod:`zope.interface` stuff, annotations and more.
Unfortunately a wrapper is not the same as the object it wraps, and answering
the inevitable questions about this difference would be confusing. Moreover,
functionality provided by :mod:`zope.interface` such as annotations would need
to be proxied. This would be extremely difficult, if not impossible.
Furthermore, we want to avoid people writing code like this in tests or their
internal utility code and failing miserably in the future if wrappers would
no longer be needed and would therefore be removed::
It is also important that developers be able to ensure that their tests
continue to work even if wrappers were to be deprecated. Consider the failure
lurking behind test code such as this::
if users['bob'].__class__.__name__ == 'WrappedMemberDataObject':
# do something
@ -160,5 +153,5 @@ Why ``delete`` instead of ``remove``?
-------------------------------------
* The underlying code uses methods that are named more similarly to *delete*
rather than to *remove*
* ``CRUD`` has *delete*, not *remove*.
rather than to *remove*.
* The ``CRUD`` verb is *delete*, not *remove*.

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/content.html>`_
so you have working references and proper formatting.
.. _plone-api-content:
plone.api.content

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/env.html>`_
so you have working references and proper formatting.
.. _plone-api-env:
plone.api.env

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/exceptions.html>`_
so you have working references and proper formatting.
.. _plone-api-errors:
plone.api.exc

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/group.html>`_
so you have working references and proper formatting.
.. _plone-api-group:
plone.api.group

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/api.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/index.html>`_
so you have working references and proper formatting.
.. currentmodule:: plone
@ -80,6 +80,9 @@ api.env
.. autosummary::
api.env.adopt_roles
api.env.adopt_user
api.env.debug_mode
api.env.test_mode
Exceptions and errors

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/portal.html>`_
so you have working references and proper formatting.
.. _plone-api-portal:
plone.api.portal

View File

@ -1,3 +1,10 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/api/user.html>`_
so you have working references and proper formatting.
.. _plone-api-user:
plone.api.user

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/content.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/content.html>`_
so you have working references and proper formatting.
.. module:: plone
@ -17,16 +17,17 @@ Content
Create content
--------------
First get the portal object that we will use as a container for new content:
To add an object, you must first have a container in which to put it. Get the
portal object, it will serve nicely:
.. code-block:: python
from plone import api
portal = api.portal.get()
If you want to create a new content item, use the :meth:`api.content.create`
method. The type attribute will automatically decide which content type
(dexterity, archetype, ...) should be created.
Create your new content item using the :meth:`api.content.create` method. The
type argument will decide which content type will be created. Both Dexterity
and Archetypes content types are supported.
.. code-block:: python
@ -36,7 +37,8 @@ method. The type attribute will automatically decide which content type
title='My Content',
container=portal)
The ``id`` of the object gets generated (in a safe way) from its ``title``.
The ``id`` of the new object is automatically and safely generated from its
``title``.
.. code-block:: python
@ -48,8 +50,8 @@ The ``id`` of the object gets generated (in a safe way) from its ``title``.
Get content object
------------------
There are several approaches of getting to your content object. Consider
the following portal structure::
There are several approaches to getting your content object. Consider the
following portal structure::
plone (portal root)
|-- blog
@ -76,8 +78,8 @@ the following portal structure::
api.content.create(container=events, type='Event', id='sprint')
You can do the following operations to get to various content objects in the
stucture above, including using :meth:`api.content.get`.
The following operations will get objects from the stucture above, including
using :meth:`api.content.get`.
.. code-block:: python
@ -98,7 +100,7 @@ stucture above, including using :meth:`api.content.get`.
# moreover, you can access content by its UID
uid = about['team'].UID()
conference = api.content.get(UID=uid)
team = api.content.get(UID=uid)
.. invisible-code-block: python
@ -108,12 +110,13 @@ stucture above, including using :meth:`api.content.get`.
self.assertTrue(about)
self.assertTrue(conference)
self.assertTrue(sprint)
self.assertTrue(team)
.. _content_find_example:
Find content object
-------------------
Find content objects
--------------------
You can use the *catalog* to search for content. Here is a simple example:
@ -127,8 +130,8 @@ You can use the *catalog* to search for content. Here is a simple example:
self.assertEqual(catalog.__class__.__name__, 'CatalogTool')
self.assertEqual(len(documents), 3)
More about how to use the catalog and what parameters it supports is written
in the `Collective Developer Documentation
More information about how to use the catalog may be found in the `Collective
Developer Documentation
<http://collective-docs.readthedocs.org/en/latest/searching_and_indexing/query.html>`_.
Note that the catalog returns *brains* (metadata stored in indexes) and not
objects. However, calling ``getObject()`` on brains does in fact give you the
@ -145,15 +148,15 @@ object.
Get content object UUID
-----------------------
An Universally Unique IDentifier (UUID) is a unique, non-human-readable
A Universally Unique IDentifier (UUID) is a unique, non-human-readable
identifier for a content object which stays on the object even if the object
is moved.
Plone uses UUIDs for storing content-to-content references and for linking by
Plone uses UUIDs for storing references between content and for linking by
UIDs, enabling persistent links.
To get a content object UUID use :meth:`api.content.get_uuid`. The following
code gets the UUID of the ``contact`` document.
To get the UUID of any content object use :meth:`api.content.get_uuid`. The
following code gets the UUID of the ``contact`` document.
.. code-block:: python
@ -172,9 +175,10 @@ code gets the UUID of the ``contact`` document.
Move content
------------
To move content around the portal structure defined above use
:meth:`api.content.move` The code below moves the ``contact`` item (with all
objects that it contains) out of folder ``about`` into the Plone portal root.
To move content around the portal structure defined above use the
:meth:`api.content.move` method. The code below moves the ``contact`` item
(with all it contains) out of the folder ``about`` and into the Plone portal
root.
.. code-block:: python
@ -190,16 +194,16 @@ objects that it contains) out of folder ``about`` into the Plone portal root.
self.assertTrue(portal['contact'])
Actually, ``move`` behaves like a filesystem move. If you pass it an ``id``
argument, you can define to what target ID the object will be moved to.
Otherwise it will be moved with the same ID that it had.
argument the object will have that new ID in it's new home. By default it will
retain its original ID.
.. _content_rename_example:
Rename content
--------------
To rename, use the :meth:`api.content.rename` method.
To rename a content object (change its ID), use the :meth:`api.content.rename`
method.
.. code-block:: python
@ -218,7 +222,7 @@ To rename, use the :meth:`api.content.rename` method.
Copy content
------------
To copy a content object, use the :meth:`api.content.copy`.
To copy a content object, use the :meth:`api.content.copy` method.
.. code-block:: python
@ -228,9 +232,9 @@ To copy a content object, use the :meth:`api.content.copy`.
api.content.copy(source=training, target=portal)
Note that the new object will have the same id as the old object (if not
stated otherwise). This is not a problem, since the new object is in a different
container.
Note that the new object will have the same ID as the old object (unless
otherwise stated). This is not a problem, since the new object is in a
different container.
.. invisible-code-block: python
@ -240,7 +244,7 @@ container.
You can also set ``target`` to source's container and set ``safe_id=True`` which
will duplicate your content object in the same container and assign it a
non-conflicting id.
new, non-conflicting ID.
.. code-block:: python
@ -258,8 +262,8 @@ non-conflicting id.
Delete content
--------------
Deleting content works by passing the object you want to delete to the
:meth:`api.content.delete` method:
To delete a content object, pass the object to the :meth:`api.content.delete`
method:
.. code-block:: python
@ -278,11 +282,13 @@ Content manipulation with the `safe_id` option
----------------------------------------------
When manipulating content with :meth:`api.content.create`,
:meth:`api.content.move` and :meth:`api.content.copy` the `safe_id` flag is
disabled by default. This means the id will be enforced, if the id is taken on
the target container the API method will raise an error.
:meth:`api.content.move` or :meth:`api.content.copy` the `safe_id` flag is
disabled by default. This means the uniqueness of IDs will be enforced. If
another object with the same ID is already present in the target container
these API methods will raise an error.
However, if the `safe_id` option is enabled, a non-conflicting id will be created.
However, if the `safe_id` option is enabled, a non-conflicting id will be
generated.
.. invisible-code-block: python
@ -299,8 +305,8 @@ However, if the `safe_id` option is enabled, a non-conflicting id will be create
Get workflow state
------------------
To find out in which workflow state your content is, use
:meth:`api.content.get_state`.
To find out the current workflow state of your content, use the
:meth:`api.content.get_state` method.
.. code-block:: python
@ -318,7 +324,8 @@ To find out in which workflow state your content is, use
Transition
----------
To transition your content into a new state, use :meth:`api.content.transition`.
To transition your content to a new workflow state, use the
:meth:`api.content.transition` method.
.. code-block:: python

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/contribute/conventions.html so you
have working references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/contribute/conventions.html>`_
so you have working references and proper formatting.
.. _conventions:
@ -297,7 +297,7 @@ Declaring dependencies
All direct dependencies should be declared in ``install_requires`` or
``extras_require`` sections in ``setup.py``. Dependencies, which are not needed for
a production environment (like "develop" or "test" dependencies) or are
optional (like "archetypes" or "dexterity" flavors of the same package) should
optional (like "Archetypes" or "Dexterity" flavors of the same package) should
go in ``extras_require``. Remember to document how to enable specific features
(and think of using ``zcml:condition`` statements, if you have such optional
features).

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/contribute/develop.html so you
have working references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/contribute/develop.html>`_
so you have working references and proper formatting.
=======================

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/about.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/contribute/index.html>`_
so you have working references and proper formatting.
==================================

View File

@ -1,3 +1,9 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/contribute/release.html>`_
so you have working references and proper formatting.
.. _releasing_a_new_version:
=======================

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/env.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/env.html>`_
so you have working references and proper formatting.
.. module:: plone
@ -70,6 +70,8 @@ To temporarily override the user which is currently active, use
"doc_owner",
)
.. _env_debug_mode_example:
Debug mode
----------
@ -84,6 +86,9 @@ To know if your zope instance is running in debug mode, use
if in_debug_mode:
print 'Zope is in debug mode'
.. _env_test_mode_example:
Test mode
---------

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/group.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/group.html>`_
so you have working references and proper formatting.
.. module:: plone
@ -28,7 +28,8 @@ To create a new portal group, use :meth:`api.group.create`.
self.assertEqual(group.id, 'staff')
When creating groups ``title``, ``description``, ``roles`` and ``groups`` are optional.
When creating groups ``title``, ``description``, ``roles`` and ``groups`` are
optional.
.. code-block:: python
@ -123,9 +124,9 @@ You can also get all groups, by using :meth:`api.group.get_groups`.
Get user's groups
-----------------
If you set the ``user`` parameter,
then :meth:`api.group.get_groups` will return
groups that the user is member of.
The groups returned may be filtered by member. By passing the ``username``
parameter, :meth:`api.group.get_groups` will return only those groups to which
the user belongs.
.. invisible-code-block: python
@ -145,12 +146,23 @@ groups that the user is member of.
self.assertEqual(groups[1].id, 'AuthenticatedUsers')
self.assertEqual(groups[2].id, 'staff')
You may also pass the user directly to :meth:`api.group.get_groups`:
from plone import api
user = api.user.get(username='jane')
groups = api.group.get_groups(user=user)
.. invisible-code-block: python
self.assertEqual(groups[0].id, 'Reviewers')
self.assertEqual(groups[1].id, 'AuthenticatedUsers')
self.assertEqual(groups[2].id, 'staff')
Get group members
-----------------
Remember to use the :meth:`api.user.get_users` method to get all users that are
members of a certain group.
Use the :meth:`api.user.get_users` method to get all the users that are
members of a group.
.. code-block:: python
@ -168,8 +180,8 @@ members of a certain group.
Delete group
------------
To delete a group, use :meth:`api.group.delete` and pass in either the groupname
or the group object you want to delete.
To delete a group, use :meth:`api.group.delete` and pass in either the
groupname or the group object you want to delete.
.. code-block:: python
@ -196,9 +208,9 @@ or the group object you want to delete.
Adding user to group
--------------------
The :meth:`api.group.add_user` method accepts either the groupname or the group
object of the target group and the username or the user object you want to add
to the group.
To add a user to a group, use the :meth:`api.group.add_user` method. This
method accepts either the groupname or the group object for the target group
and the username or the user object you want to add to the group.
.. code-block:: python
@ -209,7 +221,9 @@ to the group.
.. invisible-code-block: python
self.assertTrue('staff' in [g.id for g in api.group.get_groups(username='bob')])
self.assertTrue(
'staff' in [g.id for g in api.group.get_groups(username='bob')]
)
.. _group_remove_user_example:
@ -217,9 +231,9 @@ to the group.
Removing user from group
------------------------
The :meth:`api.group.remove_user` method accepts either the groupname or the
group object of the target group and either the username or the user object you
want to remove from the group.
To remove a user from a group, use the :meth:`api.group.remove_user` method.
This also accepts either the groupname or the group object for the target group
and either the username or the user object you want to remove from the group.
.. code-block:: python
@ -237,8 +251,8 @@ want to remove from the group.
Get group roles
---------------
The :meth:`api.group.get_roles` method is used for getting a group's roles.
By default it returns site-wide roles.
To find the roles assigned to a group, use the :meth:`api.group.get_roles`
method. By default it returns site-wide roles.
.. code-block:: python
@ -251,7 +265,7 @@ By default it returns site-wide roles.
self.assertEqual(set(EXPECTED_SITE_ROLES), set(roles))
If you pass in a content object, it will return local roles of the group
If you pass in a content object, it will return the local roles of the group
in that particular context.
.. code-block:: python
@ -276,8 +290,8 @@ in that particular context.
Grant roles to group
--------------------
The :meth:`api.group.grant_roles` allows us to grant a list of roles site-wide to the
group.
To grant roles to a group, use the :meth:`api.group.grant_roles` method. By
default, roles are granted site-wide.
.. code-block:: python
@ -294,7 +308,8 @@ group.
self.assertEqual(set(EXPECTED_SITE_ROLES), set(roles))
If you pass in a content object, it will grant these roles in that particular context.
If you pass in a content object, roles will be assigned in that particular
context.
.. code-block:: python
@ -317,8 +332,8 @@ If you pass in a content object, it will grant these roles in that particular co
Revoke roles from group
-----------------------
The :meth:`api.group.revoke_roles` allows us to revoke a list of roles from the
group.
To revoke roles already granted to a group, use the
:meth:`api.group.revoke_roles` method.
.. code-block:: python
@ -333,7 +348,8 @@ group.
self.assertEqual(set(EXPECTED_SITE_ROLES), set(roles))
If you pass in a content object, it will grant these roles in that particular context.
If you pass in a content object, it will revoke roles granted in that
particular context.
.. code-block:: python
@ -352,5 +368,5 @@ If you pass in a content object, it will grant these roles in that particular co
Further reading
---------------
For more information on possible flags and usage options please see the full
:ref:`plone-api-group` specification.
For more information on possible flags and complete options please see the
full :ref:`plone-api-group` specification.

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/index.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/index.html>`_
so you have working references and proper formatting.
===========
A Plone API

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/portal.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/portal.html>`_
so you have working references and proper formatting.
.. module:: plone

View File

@ -1,8 +1,8 @@
.. admonition:: GitHub-only
WARNING: If you are reading this on GitHub, DON'T! Read it on api.plone.org:
http://developer.plone.org/reference_manuals/external/plone.api/user.html so you have working
references and proper formatting.
WARNING: If you are reading this on GitHub, DON'T! Read the documentation
at `api.plone.org <http://developer.plone.org/reference_manuals/external/plone.api/user.html>`_
so you have working references and proper formatting.
.. module:: plone

View File

@ -163,12 +163,18 @@ class _GlobalRoleOverridingContext(object):
def debug_mode():
"""Returns True if your zope instance is running in debug mode."""
"""Returns True if your zope instance is running in debug mode.
:Example: :ref:`env_debug_mode_example`
"""
return Globals.DevelopmentMode
def test_mode():
"""Returns True if you are running the zope test runner."""
"""Returns True if you are running the zope test runner.
:Example: :ref:`env_test_mode_example`
"""
from plone.api import env
if env.IS_TEST is None: