Skip to content
This repository has been archived by the owner on Oct 28, 2019. It is now read-only.

Commit

Permalink
Build API docs using sphinx autodoc
Browse files Browse the repository at this point in the history
This requires turning off "nit-picky" mode due to references to types unknown
to sphinx without getting intersphinx involved (e.g. str, django.db.models.Model,
etc.)

I added a little extension to napoleon to support our "Fields" and "Relations"
sections that we use in our Django models, which made it easy to test different
Sphinx methods of exposing class attributes, and also lets us use napoleon. :)

closes #2327
https://pulp.plan.io/issues/2327
  • Loading branch information
seandst committed Nov 9, 2016
1 parent a7979ba commit 8c23b32
Show file tree
Hide file tree
Showing 26 changed files with 608 additions and 388 deletions.
49 changes: 20 additions & 29 deletions app/pulp/app/fields.py
Expand Up @@ -16,17 +16,13 @@ def from_db_value(self, value, *args, **kwargs):
"""
Converts a value as returned by the database to a Python object
:param value: The value to convert to Python
:type value: object
Args:
value: DB value to convert to Python
args: unused positional arguments
kwargs: unused keyword arguments
:param args: unused positional arguments
:type args: list
:param kwargs: unused keyword arguments
:type kwargs: dict
:return: A Python representation of value
:rtype: object
Returns:
Python representation of ``value``
"""
if isinstance(value, six.string_types):
return self.to_python(value)
Expand All @@ -36,29 +32,25 @@ def to_python(self, value):
"""
Converts the value into the correct Python object
:param value: The value to convert to Python
:type value: object
Args:
value: The JSON-serializeable value to convert to Python
:return: A Python representation of value
:rtype: object
Returns:
Python representation of value
"""
return json.loads(value)

def get_db_prep_value(self, value, *args, **kwargs):
"""
Converts value to a backend-specific value
:param value: The value to be converted
:type value: object
:param args: unused positional arguments
:type args: list
Args:
value: value to convert
args: unused positional arguments
kwargs: unused keyword arguments
:param kwargs: unused keyword arguments
:type kwargs: dict
:return: json string representing the object
:rtype: str
Returns:
JSON string representation of ``value``
"""
if value is None:
return None
Expand All @@ -68,11 +60,10 @@ def value_to_string(self, obj):
"""
Converts obj to a string. Used to serialize the value of the field
:param obj: The object to be converted
:type obj: object
:return: Serialized value
:rtype: str
Args:
obj: The JSON-serializable object to be converted
Returns:
str: JSON Serialized value
"""
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value, None)
30 changes: 15 additions & 15 deletions app/pulp/app/logs.py
Expand Up @@ -50,8 +50,8 @@ def emit(self, record):
records. For each of those records, it will also verify that they are no longer than
MAX_MSG_LENGTH octets. If they are, it will break them up at that boundary as well.
:param record: The record to be logged via syslog
:type record: logging.LogRecord
Args:
record (logging.LogRecord): The record to be logged via syslog
"""
if record.exc_info:
trace = self.formatter.formatException(record.exc_info)
Expand Down Expand Up @@ -92,10 +92,12 @@ def _calculate_formatter_buffer(self, record):
Given a record with no exc_info, determine how many bytes the formatter will add to it so
that we know how much room to leave when trimming messages.
:param record: An example record that can be used to find the formatter buffer
:type record: logging.LogRecord
:return: The difference between the rendered record length and the message length.
:rtype: int
Args:
record (logging.LogRecord): An example record that can be used to find the formatter
buffer
Returns:
int: The difference between the rendered record length and the message length.
"""
formatted_record = self.format(record)
formatted_record = formatted_record.encode('utf8')
Expand All @@ -111,16 +113,14 @@ def _cut_message(message, formatter_buffer, msg_id):
multi-byte characters apart. This method also encodes unicode objects with UTF-8 as a side
effect, because length limits are specified in octets, not characters.
:param message: A message that needs to be broken up if it's too long
:type message: str (Python 2 `unicode`)
:param formatter_buffer: How many octets of room to leave on each message to account for
Args:
message (str): A message that needs to be broken up if it's too long
formatter_buffer (int): How many octets of room to leave on each message to account for
extra data that the formatter will add to this message
:type formatter_buffer: int
:param msg_id: Process and thread id that will be prepended to multi line messages
:type msg_id: string
:return: A generator of bytes objects, each of which is no longer than
MAX_MSG_LENGTH - formatter_buffer octets.
:rtype: generator
msg_id (str): Process and thread id that will be prepended to multi line messages
Returns:
generator of bytes objects, each of which is no longer than
"""
max_length = CompliantSysLogHandler.MAX_MSG_LENGTH - formatter_buffer
message = message.encode('utf8')
Expand Down
22 changes: 18 additions & 4 deletions app/pulp/app/models/base.py
Expand Up @@ -10,10 +10,15 @@ class Model(models.Model):
Uses UUID as its primary key field, named "id" to mimic default Django model
behavior.
Fields:
id: UUID ID Primary Key Field
References:
https://docs.djangoproject.com/en/1.8/topics/db/models/#automatic-primary-key-fields
https://docs.djangoproject.com/en/1.8/ref/models/fields/#uuidfield
https://www.postgresql.org/docs/current/static/datatype-uuid.html
* https://docs.djangoproject.com/en/1.8/topics/db/models/#automatic-primary-key-fields
* https://docs.djangoproject.com/en/1.8/ref/models/fields/#uuidfield
* https://www.postgresql.org/docs/current/static/datatype-uuid.html
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# ...we have zero interest in using a mongo-specific datatype (ObjectId) as
Expand All @@ -29,6 +34,15 @@ class MasterModel(Model):
Provides methods for casting down to detail types, back up to the master type,
as well as a model field for tracking the type.
Attributes:
MasterModel.TYPE (str): Default constant value saved into the ``type``
field of Model instances
Fields:
type: The user-facing string identifying the detail type of this model
Warning:
Subclasses of this class rely on there being no other parent/child Model
relationships than the Master/Detail relationship. All subclasses must use
Expand Down Expand Up @@ -111,7 +125,7 @@ def master_model(options):
"""
The Master model class of this Model's Master/Detail relationship.
Accessible at <model_class>._meta.master_model, the Master model class in a Master/Detail
Accessible at ``<model_class>._meta.master_model``, the Master model class in a Master/Detail
relationship is the most generic non-abstract Model in this model's multiple-table chain
of inheritance.
Expand Down
18 changes: 8 additions & 10 deletions app/pulp/app/models/catalog.py
Expand Up @@ -10,23 +10,21 @@

class DownloadCatalog(Model):
"""
Each :class:`DownloadCatalog` maps an :class:`Artifact` to a URL where
it is stored remotely and to the :class:`Importer` which contains the
network configuration required to access that URL.
Each :class:`DownloadCatalog` maps an :class:`pulp.app.models.content.Artifact` to a URL where
it is stored remotely and to the :class:`pulp.app.models.repository.Importer` which contains
the network configuration required to access that URL.
Fields:
:cvar url: The URL used to download the related artifact.
:type url: django.db.models.TextField
url (models.TextField): The URL used to download the related artifact.
Relations:
:cvar artifact: The artifact that is expected to be present at ``url``.
:type artifact: pulp.app.models.Artifact
artifact (Artifact): The artifact that is expected to be present at
``url``.
importer (Importer): The importer that contains the
configuration necessary to access ``url``.
:cvar importer: The importer that contains the configuration necessary
to access ``url``.
:type importer: pulp.app.models.Importer
"""
# Although there is a Django field for URLs based on CharField, there is
# not technically any limit on URL lengths so it's simplier to allow any
Expand Down
16 changes: 5 additions & 11 deletions app/pulp/app/models/consumer.py
Expand Up @@ -13,19 +13,14 @@ class Consumer(Model):
Fields:
:cvar name: The consumer common name.
:type name: models.TextField
:cvar: description: An optional description.
:type: models.TextField
name (models.TextField): The consumer common name.
description (models.TextField): An optional description.
Relations:
:cvar notes: Arbitrary information about the consumer.
:type notes: GenericKeyValueRelation
notes (GenericKeyValueRelation): Arbitrary information about the consumer.
publishers (models.ManyToManyField): Associated publishers.
:cvar publishers: Associated publishers.
:type publishers: models.ManyToManyField
"""
name = models.TextField(db_index=True, unique=True)
description = models.TextField(blank=True)
Expand All @@ -49,8 +44,7 @@ class ConsumerContent(Model):
Relations:
:cvar consumer: The consumer on which the content is installed.
:type consumer: models.ForeignKey
consumer (models.ForeignKey): The consumer on which the content is installed.
"""
consumer = models.ForeignKey(Consumer, on_delete=models.CASCADE)

Expand Down
64 changes: 20 additions & 44 deletions app/pulp/app/models/content.py
Expand Up @@ -14,13 +14,13 @@ class Content(MasterModel):
"""
A piece of managed content.
:cvar natural_key_fields: Tuple of natural fields. Must be: models.Field.
:type natural_key_fields: tuple
Attributes:
nature_key_fields (tuple): Natural key fields. Must be models.Field subclasses.
Relations:
:cvar notes: Arbitrary information stored with the content.
:type notes: GenericKeyValueRelation
notes (GenericKeyValueRelation): Arbitrary information stored with the content.
"""
TYPE = 'content'

Expand Down Expand Up @@ -67,49 +67,25 @@ class Artifact(Model):
Fields:
:cvar file: The stored file.
:type file: models.FileField
:cvar downloaded: The associated file has been successfully downloaded.
:type downloaded: BooleanField
:cvar requested: The associated file has been requested by a client at
least once.
:type requested: BooleanField
:cvar relative_path: The artifact's path relative to the associated
:class:`Content`. This path is incorporated in
the absolute storage path of the file and its
published path relative to the root publishing
directory. At a minimum the path will contain the
file name but may also include sub-directories.
:type relative_path: models.TextField
:cvar size: The size of the file in bytes.
:type size: models.IntegerField
:cvar md5: The MD5 checksum of the file.
:type md5: models.CharField
:cvar sha1: The SHA-1 checksum of the file.
:type sha1: models.CharField
:cvar sha224: The SHA-224 checksum of the file.
:type sha224: models.CharField
:cvar sha256: The SHA-256 checksum of the file.
:type sha256: models.CharField
:cvar sha384: The SHA-384 checksum of the file.
:type sha384: models.CharField
:cvar sha512: The SHA-512 checksum of the file.
:type sha512: models.CharField
file (models.FileField): The stored file.
downloaded (models.BooleanField): The associated file has been successfully downloaded.
requested (models.BooleanField): The associated file has been requested by a client at
least once.
relative_path (models.TextField): The artifact's path relative to the associated
:class:`Content`. This path is incorporated in the absolute storage path of the file
and its published path relative to the root publishing directory. At a minimum the path
will contain the file name but may also include sub-directories.
size (models.IntegerField): The size of the file in bytes.
md5 (models.CharField): The MD5 checksum of the file.
sha1 (models.CharField): The SHA-1 checksum of the file.
sha224 (models.CharField): The SHA-224 checksum of the file.
sha256 (models.CharField): The SHA-256 checksum of the file.
sha384 (models.CharField): The SHA-384 checksum of the file.
sha512 (models.CharField): The SHA-512 checksum of the file.
Relations:
:cvar content: The associated content.
:type content: Content
content (models.ForeignKey): The associated content.
"""

# Note: The FileField does not support unique indexes and has
Expand Down
2 changes: 1 addition & 1 deletion app/pulp/app/models/generic.py
Expand Up @@ -43,7 +43,7 @@ class GenericKeyValueMutableMapping(MutableMapping):
``__contains__`` falls back to the manager's ``exists`` method
``items`` returns key/value pairs directly from model instances, rather than
keys and values are stored in ``TextField``s, and will automatically be coerced to strings
keys and values are stored in a ``TextField``, and will automatically be coerced to string
when saved to the database.
"""
Expand Down
37 changes: 15 additions & 22 deletions app/pulp/app/models/progress.py
Expand Up @@ -21,24 +21,18 @@ class ProgressReport(Model):
Fields:
:cvar message: A short message for the progress update, typically shown to the user. (required)
:type message: models.TextField
:cvar state: The state of the progress update. Defaults to `WAITING`. This field uses a limited
set of choices of field states. See `STATES` for possible states.
:type state: models.TextField
:cvar total: The total count of items to be handled by the ProgressBar (required)
:type total: models.IntegerField
:cvar done: The count of items already processed. Defaults to 0.
:type done: models.IntegerField
message (models.TextField): short message for the progress update, typically
shown to the user. (required)
state (models.TextField): The state of the progress update. Defaults to `WAITING`. This
field uses a limited set of choices of field states. See `STATES` for possible states.
total: (models.IntegerField) The total count of items to be handled by the ProgressBar
(required)
done (models.IntegerField): The count of items already processed. Defaults to 0.
Relations:
:cvar task: The task associated with this progress report. If left unset when save() is called
it will be set to the current task_id.
:type task: models.ForeignKey
task: The task associated with this progress report. If left unset when save() is called
it will be set to the current task_id.
"""
WAITING = 'waiting'
SKIPPED = 'skipped'
Expand Down Expand Up @@ -69,10 +63,8 @@ def save(self, *args, **kwargs):
If the task_id is already set it will not be updated. If it is unset and this is running
inside of a task it will be auto-set prior to saving.
:param args: positional arguments to be passed on to the real save
:type args: list
:param kwargs: keyword arguments to be passed on to the real save
:type kwargs: dict
args (list): positional arguments to be passed on to the real save
kwargs (dict): keyword arguments to be passed on to the real save
"""
if self.task_id is None:
self.task_id = Task.objects.get(id=get_current_task_id())
Expand Down Expand Up @@ -216,10 +208,11 @@ def iter(self, iter):
>>> for file in progress_bar.iter(files_iterator):
>>> handle(file)
:param iter: The iterator to loop through while incrementing
:type iter: iterator
Args:
iter (iterator): The iterator to loop through while incrementing
:return: generator which yields items out of the argument iter
Returns:
generator of ``iter`` argument items
"""
for x in iter:
yield x
Expand Down

0 comments on commit 8c23b32

Please sign in to comment.