added information about the naming conventions in schema.py stable
authorAlexandre Fayolle <alexandre.fayolle@logilab.fr>
Mon, 05 Apr 2010 09:06:16 +0200
branchstable
changeset 5145 bfa4d775219f
parent 5144 5a09bea07302
child 5146 fe56baf63ecb
added information about the naming conventions in schema.py also: * some typo fix * note about ObjectRelation soon being deprecated * clarified a few hazy points
doc/book/en/development/datamodel/definition.rst
--- a/doc/book/en/development/datamodel/definition.rst	Fri Apr 02 17:27:53 2010 +0200
+++ b/doc/book/en/development/datamodel/definition.rst	Mon Apr 05 09:06:16 2010 +0200
@@ -11,21 +11,20 @@
 
 At this point, it is important to make clear the difference between
 *relation type* and *relation definition*: a *relation type* is only a relation
-name with potentially other additionnal properties (see below), whereas a
+name with potentially other additional properties (see below), whereas a
 *relation definition* is a complete triplet
 "<subject entity type> <relation type> <object entity type>".
-A relation type could have been implied if none is related to a
-relation definition of the schema.
 
-Also, it should be clear that to properly handle data migration, an instance'schema
-is stored in the database, so the python schema file used to defined it are only readen
+Also, it should be clear that to properly handle data migration, an
+instance's schema
+is stored in the database, so the python schema file used to defined it is only read
 when the instance is created or upgraded.
 
-The following built-in types are available : `String`, `Int`, `Float`,
+The following built-in types are available: `String`, `Int`, `Float`,
 `Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte`
 and `Password`.
 
-You'll also have access to :ref:`base cubicweb entity types <CWBaseEntityTypes>`.
+You'll also have access to :ref:`base CubicWeb entity types <CWBaseEntityTypes>`.
 
 The instance schema is accessible through the .schema attribute of the
 `vregistry`.  It's an instance of :class:`cubicweb.schema.Schema`, which
@@ -33,117 +32,127 @@
 
 :note:
   In previous yams versions, almost all classes where available without
-  any import, but the should now be explicitely imported.
+  any import, but the should now be explicitly imported.
 
 
 Entity type
 ~~~~~~~~~~~
-It's an instance of :class:`yams.schema.EntitySchema`. Each entity types has
-a set of attributes and relation and some permissions, defining who can add, read,
+An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
+a set of attributes and relations, and some permissions which define who can add, read,
 update or delete entities of this type.
 
 XXX yams inheritance
 
 Relation type
 ~~~~~~~~~~~~~
-It's an instance of :class:`yams.schema.RelationSchema`. A relation type is simply
-a semantic definition of a kind of relationship that may occurs in your application.
+A relation type is an instance of :class:`yams.schema.RelationSchema`. A relation type is simply
+a semantic definition of a kind of relationship that may occur in an application.
 
-It's important to choose a good name, at least to avoid conflicts with some semantically
-different relation defined in other cubes (since we've no namespace yet).
+It is important to choose a good name, at least to avoid conflicts with some semantically
+different relation defined in other cubes (since we've no name space yet).
 
-A relation type hold the following properties (which are hence shared between all
+A relation type holds the following properties (which are hence shared between all
 relation definitions of that type):
 
-* `inlined` : boolean handling the physical optimization for archiving
+* `inlined`: boolean handling the physical optimization for archiving
   the relation in the subject entity table, instead of creating a specific
   table for the relation. This applies to relations where cardinality
   of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
   definitions.
 
-* `symmetric` : boolean indicating that the relation is symmetrical, which
+* `symmetric`: boolean indicating that the relation is symmetrical, which
   means that `X relation Y` implies `Y relation X`.
 
 
 Relation definition
 ~~~~~~~~~~~~~~~~~~~
-It's an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet
+A relation definition is an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet
 "<subject entity type> <relation type> <object entity type>".
 
+When creating a new instance of that class, the corresponding
+:class:`RelationType` instance is created on the fly if necessary.
+
+
 Properties
 ``````````
 
-* Optional properties for attributes and relations :
+* Optional properties for attributes and relations:
 
-  - `description` : a string describing an attribute or a relation. By default
+  - `description`: a string describing an attribute or a relation. By default
     this string will be used in the editing form of the entity, which means
     that it is supposed to help the end-user and should be flagged by the
     function `_` to be properly internationalized.
 
-  - `constraints` : a list of conditions/constraints that the relation has to
+  - `constraints`: a list of conditions/constraints that the relation has to
     satisfy (c.f. `Constraints`_)
 
-  - `cardinality` : a two character string which specify the cardinality of the
+  - `cardinality`: a two character string specifying the cardinality of the
     relation. The first character defines the cardinality of the relation on
     the subject, and the second on the object. When a relation can have
     multiple subjects or objects, the cardinality applies to all,
     not on a one-to-one basis (so it must be consistent...). The possible
-    values are inspired from regular expression syntax :
+    values are inspired from regular expression syntax:
 
     * `1`: 1..1
     * `?`: 0..1
     * `+`: 1..n
     * `*`: 0..n
 
-* optional properties for attributes :
+* optional properties for attributes:
 
-  - `unique` : boolean indicating if the value of the attribute has to be unique
+  - `unique`: boolean indicating if the value of the attribute has to be unique
     or not within all entities of the same type (false by default)
 
-  - `indexed` : boolean indicating if an index needs to be created for this
+  - `indexed`: boolean indicating if an index needs to be created for this
     attribute in the database (false by default). This is useful only if
     you know that you will have to run numerous searches on the value of this
     attribute.
 
-  - `default` : default value of the attribute. In case of date types, the values
+  - `default`: default value of the attribute. In case of date types, the values
     which could be used correspond to the RQL keywords `TODAY` and `NOW`.
 
-* optional properties of type `String` :
+* optional properties for type `String` attributes:
 
-  - `fulltextindexed` : boolean indicating if the attribute is part of
+  - `fulltextindexed`: boolean indicating if the attribute is part of
     the full text index (false by default) (*applicable on the type `Byte`
     as well*)
 
-  - `internationalizable` : boolean indicating if the value of the attribute
+  - `internationalizable`: boolean indicating if the value of the attribute
     is internationalizable (false by default)
 
-* optional properties for relations :
+* optional properties for relations:
 
-  - `composite` : string indicating that the subject (composite == 'subject')
+  - `composite`: string indicating that the subject (composite == 'subject')
     is composed of the objects of the relations. For the opposite case (when
     the object is composed of the subjects of the relation), we just set
     'object' as value. The composition implies that when the relation
     is deleted (so when the composite is deleted, at least), the composed are also deleted.
 
-  - `fti_container`: XXX feed me
+  - `fulltext_container`: string indicating if the value if the full text
+    indexation of the entity on one end of the relation should be used
+    to find the entity on the other end. The possible values are
+    'subject' or 'object'. For instance the use_email relation has
+    that property set to 'subject', since when performing a full text
+    search people want to find the entity using an email address, and not
+    the entity representing the email address.
 
 Constraints
 ```````````
 
-By default, the available constraint types are :
+By default, the available constraint types are:
 
 General Constraints
 ......................
 
-* `SizeConstraint` : allows to specify a minimum and/or maximum size on
+* `SizeConstraint`: allows to specify a minimum and/or maximum size on
   string (generic case of `maxsize`)
 
-* `BoundConstraint` : allows to specify a minimum and/or maximum value on
+* `BoundConstraint`: allows to specify a minimum and/or maximum value on
   numeric types
 
-* `UniqueConstraint` : identical to "unique=True"
+* `UniqueConstraint`: identical to "unique=True"
 
-* `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
+* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
 
 XXX Attribute, TODAY, NOW
 
@@ -159,39 +168,19 @@
 displayed when the constraint fails. As RQLVocabularyConstraint never fails the
 third argument is not available.
 
-* `RQLConstraint` : allows to specify a RQL query that has to be satisfied
+* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
   by the subject and/or the object of relation. In this query the variables
-  `S` and `O` are reserved for the entities subject and object of the
-  relation.
+  `S` and `O` are reserved for the relation subject and object entities.
 
-* `RQLVocabularyConstraint` : similar to the previous type of constraint except
+* `RQLVocabularyConstraint`: similar to the previous type of constraint except
   that it does not express a "strong" constraint, which means it is only used to
   restrict the values listed in the drop-down menu of editing form, but it does
   not prevent another entity to be selected.
 
-* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an
+* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
   attribute is unique in a specific context. The Query must **never** return more
   than a single result to be satisfied. In this query the variables `S` is
-  reserved for the entity subject of the relation. The other variable should be
-  specified with the second constructor argument (mainvars). This constraints
-  should be used when UniqueConstraint doesn't fit. Here is a simple example ::
-
-    # Check that in the same Workflow each state's name is unique.  Using
-    # UniqueConstraint (or unique=True) here would prevent states in different
-    # workflows to have the same name.
-
-    # With: State S, Workflow W, String N ; S state_of W, S name N
-
-    RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
-                        mainvars='Y',
-                        msg=_('workflow already have a state of that name'))
-
-
-
-* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an
-  attribute is unique in a specific context. The Query must **never** return more
-  than a single result to be satisfied. In this query the variables `S` is
-  reserved for the entity subject of the relation. The other variable should be
+  reserved for the relation subject entity. The other variables should be
   specified with the second constructor argument (mainvars). This constraints
   should be used when UniqueConstraint doesn't fit. Here is a simple example ::
 
@@ -215,7 +204,7 @@
 The security model
 ~~~~~~~~~~~~~~~~~~
 
-The security model of `cubicWeb` is based on `Access Control List`.
+The security model of `CubicWeb` is based on `Access Control List`.
 The main principles are:
 
 * users and groups of users
@@ -225,24 +214,25 @@
 
 For *CubicWeb* in particular:
 
-* we associate rights at the enttities/relations schema level
-* for each entity, we distinguish four kind of permissions: read,
-  add, update and delete
-* for each relation, we distinguish three kinds of permissions: read,
-  add and delete (we can not modify a relation)
-* the basic groups are: Administrators, Users and Guests
-* by default, users belong to the group Users
-* there is a virtual group called `Owners` to which we
-  can associate only deletion and update permissions
-* we can not add users to the `Owners` group, they are
-  implicitly added to it according to the context of the objects
-  they own
-* the permissions of this group are only checked on update/deletion
-  actions if all the other groups the user belongs to does not provide
-  those permissions
+* we associate rights at the entities/relations schema level
+* for each entity, we distinguish four kinds of permissions: `read`,
+  `add`, `update` and `delete`
+* for each relation, we distinguish three kinds of permissions: `read`,
+  `add` and `delete` (it is not possible to `modify` a relation)
+* the default groups are: `administrators`, `users` and `guests`
+* by default, users belong to the `users` group
+* there is a virtual group called `owners` to which we
+  can associate only `delete` and `update` permissions
+
+  * we can not add users to the `Owners` group, they are
+    implicitly added to it according to the context of the objects
+    they own
+  * the permissions of this group are only checked on `update`/`delete`
+    actions if all the other groups the user belongs to do not provide
+    those permissions
 
 Setting permissions is done with the attribute `__permissions__` of entities and
-relation types. It defines a dictionary where the keys are the access types
+relation types. The value of this attribute is a dictionary where the keys are the access types
 (action), and the values are the authorized groups or expressions.
 
 For an entity type, the possible actions are `read`, `add`, `update` and
@@ -252,7 +242,7 @@
 
 For each access type, a tuple indicates the name of the authorized groups and/or
 one or multiple RQL expressions to satisfy to grant access. The access is
-provided if the user is in one of the listed groups or one of if the RQL condition
+provided if the user is in one of the listed groups or if one of the RQL condition
 is satisfied.
 
 The standard user groups
@@ -264,14 +254,14 @@
 
 * `managers`
 
-* `owners` : virtual group corresponding to the entity's owner.
+* `owners`: virtual group corresponding to the entity's owner.
   This can only be used for the actions `update` and `delete` of an entity
   type.
 
 It is also possible to use specific groups if they are defined in the
-precreate of the cube (``migration/precreate.py``). Defining groups in
-postcreate or even later makes them NOT available for security
-purposes (in this case, an `sync_schema_props_perms` command have to
+precreate script of the cube (``migration/precreate.py``). Defining groups in
+postcreate script or later makes them unavailable for security
+purposes (in this case, an `sync_schema_props_perms` command has to
 be issued in a CubicWeb shell).
 
 
@@ -280,13 +270,13 @@
 It is possible to define RQL expression to provide update permission
 (`add`, `delete` and `update`) on relation and entity types.
 
-RQL expression for entity type permission :
+RQL expression for entity type permission:
 
 * you have to use the class `ERQLExpression`
 
 * the used expression corresponds to the WHERE statement of an RQL query
 
-* in this expression, the variables X and U are pre-defined references
+* in this expression, the variables `X` and `U` are pre-defined references
   respectively on the current entity (on which the action is verified) and
   on the user who send the request
 
@@ -297,19 +287,19 @@
   to this variable
 
 For RQL expressions on a relation type, the principles are the same except
-for the following :
+for the following:
 
 * you have to use the class `RRQLExpression` in the case of a non-final relation
 
-* in the expression, the variables S, O and U are pre-defined references
+* in the expression, the variables `S`, `O` and `U` are pre-defined references
   to respectively the subject and the object of the current relation (on
   which the action is being verified) and the user who executed the query
 
 * we can also define rights over attributes of an entity (non-final relation),
-  knowing that :
+  knowing that:
 
   - to define RQL expression, we have to use the class `ERQLExpression`
-    in which X represents the entity the attribute belongs to
+    in which `X` represents the entity the attribute belongs to
 
   - the permissions `add` and `delete` are equivalent. Only `add`/`read`
     are actually taken in consideration.
@@ -333,7 +323,7 @@
 Use of RQL expression for reading rights
 ````````````````````````````````````````
 
-The principles are the same but with the following restrictions :
+The principles are the same but with the following restrictions:
 
 * we can not use `RRQLExpression` on relation types for reading
 
@@ -348,19 +338,28 @@
 Entity type definition
 ~~~~~~~~~~~~~~~~~~~~~~
 
-An entity type is defined by a Python class which inherits from `EntityType`.
-The class definition contains the description of attributes and relations
-for the defined entity type.
-The class name corresponds to the entity type name. It is exepected to be
-defined in the module ``mycube.schema``.
+An entity type is defined by a Python class which inherits from
+:class:`yams.buildobjs.EntityType`.  The class definition contains the
+description of attributes and relations for the defined entity type.
+The class name corresponds to the entity type name. It is expected to
+be defined in the module ``mycube.schema``.
+
+:Note on schema definition:
+
+ The code in ``mycube.schema`` is not meant to be executed. The class
+ EntityType mentioned above is different from the EntitySchema class
+ described in the previous chapter. EntityType is a helper class to
+ make Entity definition easier. Yams will process EntityType classes
+ and create EntitySchema instances from these class definitions. Similar
+ manipulation happen for relations.
 
 When defining a schema using python files, you may use the following shortcuts:
 
-- `required` : boolean indicating if the attribute is required, eg subject cardinality is '1'
+- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
 
-- `vocabulary` : specify static possible values of an attribute
+- `vocabulary`: specify static possible values of an attribute
 
-- `maxsize` : integer providing the maximum size of a string (no limit by default)
+- `maxsize`: integer providing the maximum size of a string (no limit by default)
 
 For example:
 
@@ -382,6 +381,20 @@
 birth and a relation that connects a `Person` to another entity of type
 `Company` through the semantic `works_for`.
 
+:Naming convention:
+
+ Entity class names must start with an uppercase letter. The common
+ usage is to use ``CamelCase`` names.
+
+ Attribute and relation names must start with a lowercase letter. The
+ common usage is to use ``underscore_separated_words``. Attribute and
+ relation names starting with a single underscore are permitted, to
+ denote a somewhat "protected" or "private" attribute.
+
+ In any case, identifiers starting with "CW" or "cw" are reserved for
+ internal use by the framework.
+
+
 The name of the Python attribute corresponds to the name of the attribute
 or the relation in *CubicWeb* application.
 
@@ -390,29 +403,16 @@
     attr_name = attr_type(properties)
 
 where `attr_type` is one of the type listed above and `properties` is
-a list of the attribute needs to statisfy (see `Properties`_
+a list of the attribute needs to satisfy (see `Properties`_
 for more details).
 
-
-* relations can be defined by using `ObjectRelation` or `SubjectRelation`.
-  The first argument of `SubjectRelation` or `ObjectRelation` gives respectively
-  the object/subject entity type of the relation. This could be :
-
-  * a string corresponding to an entity type
-
-  * a tuple of string corresponding to multiple entity types
-
-  * special string such as follows :
-
-    - "**" : all types of entities
-    - "*" : all types of non-meta entities
-    - "@" : all types of meta entities but not system entities (e.g. used for
-      the basic schema description)
-
 * it is possible to use the attribute `meta` to flag an entity type as a `meta`
   (e.g. used to describe/categorize other entities)
 
-*Note* : if you end up with an `if` in the definition of your entity, this probably
+.. XXX the paragraph below needs clarification and / or moving out in
+.. another place
+
+*Note*: if you end up with an `if` in the definition of your entity, this probably
 means that you need two separate entities that implement the `ITree` interface and
 get the result from `.children()` which ever entity is concerned.
 
@@ -440,20 +440,49 @@
     subject = '*'
     object = 'CWUser'
 
-In the case of simultaneous relations definitions, `subject` and `object`
-can both be equal to the value of the first argument of `SubjectRelation`
-and `ObjectRelation`.
+If provided, the `subject` and `object` attributes denote the subject
+and object of the various relation definitions related to the relation
+type. Allowed values for these attributes are:
+
+* a string corresponding to an entity type
+* a tuple of string corresponding to multiple entity types
+* special string such as follows:
+
+  - "**": all types of entities
+  - "*": all types of non-meta entities
+  - "@": all types of meta entities but not system entities (e.g. used for
+    the basic schema description)
 
 When a relation is not inlined and not symmetrical, and it does not require
-specific permissions, its definition (by using `SubjectRelation` and
-`ObjectRelation`) is all we need.
+specific permissions, it can be defined using a `SubjectRelation`
+attribute in the EntityType class. The first argument of `SubjectRelation` gives
+the entity type for the object of the relation.
+
+:Naming convention:
+
+ Although this way of defining relations uses a Python class, the
+ naming convention defined earlier prevails over the PEP8 conventions
+ used in the framework: relation type class names use
+ ``underscore_separated_words``. 
 
+:Historical note:
+
+   It has been historically possible to use `ObjectRelation` which
+   defines a relation in the opposite direction. This feature is soon to be
+   deprecated and therefore should not be used in newly written code.
+
+:Future deprecation note:
+
+  In an even more remote future, it is quite possible that the
+  SubjectRelation shortcut will become deprecated, in favor of the
+  RelationType declaration which offers some advantages in the context
+  of reusable cubes.
 
 Definition of permissions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 The entity type `CWPermission` from the standard library
 allows to build very complex and dynamic security architectures. The schema of
-this entity type is as follow :
+this entity type is as follow:
 
 .. sourcecode:: python
 
@@ -461,12 +490,12 @@
         """entity type that may be used to construct some advanced security configuration
         """
         name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
- require_group = SubjectRelation('CWGroup', cardinality='+*',
+        require_group = SubjectRelation('CWGroup', cardinality='+*',
                                         description=_('groups to which the permission is granted'))
- require_state = SubjectRelation('State',
+        require_state = SubjectRelation('State',
                                         description=_("entity's state in which the permission is applicable"))
         # can be used on any entity
- require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
+        require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
                                             description=_("link a permission to the entity. This "
                                                           "permission should be used in the security "
                                                           "definition of the entity's type to be useful."))
@@ -502,7 +531,7 @@
 
 This configuration indicates that an entity `CWPermission` named
 "add_version" can be associated to a project and provides rights to create
-new versions on this project to specific groups. It is important to notice that :
+new versions on this project to specific groups. It is important to notice that:
 
 * in such case, we have to protect both the entity type "Version" and the relation
   associating a version to a project ("version_of")