From BlenderWiki

Jump to: navigation, search

BPy API Cleanup 2006

This page is for discussion and planning for the API cleanup.

Motivation: both Python and the BPy API have evolved over time. Time for a little cleanup and integration!

Originally, Python made a large distinction between classes and user-defined like our BPy types. This distinction is gradually being erased as types and classes become similar. As part of this process, certain old, ad hoc features like using a __members__ attribute to document type members has been deprecated.

For BPy, a lot good work has been done over the years, but it has not always been done with a view of the whole API in mind. The result can be a little like a coral reef that slowly accumulates new parts and the occasional shipwreck. Also, since BPy is designed as a thin wrapper around Blender's data and functions, as parts of Blender get re-written, BPy needs to adapt. Lastly, our collective skills at embedded Python have improved dramatically.

  • Principles and Goals for the Cleanup:
  • migrate from getStuff() / setStuff() style to tp_getset
  • throw exceptions instead of returning status codes
  • use of constants instead of strings for parameters
  • nicer interface to bitmasks
  • a naming convention for attributes, constants, etc.
  • use of constructors instead of New()
  • use of doxygen to document bpy source

Software Development in a Nutshell

  1. make a plan
  2. write down the plan
  3. follow the plan

API Definition

By writing the documentation before we start our cleanup coding, we get two things: A design document we can work from and a look at the entire API. This becomes the "write done the plan" part of the process.

This will not be as much work as it sounds like. Essentially, we will edit existing epydoc, removing the old cruft and adding the new exceptions, constants and attribute names.

Naming Conventions

Principle: the Bpy API should be familiar to someone familiar with the Blender UI. Whenever possible, we use names from the Blender UI. A good naming convention makes unknown names 'obvious'.

Types of names exposed to the user in BPy are:

  • modules
  • types & classes
  • methods
  • attributes
  • constants

Names in BPy source:

  • modules
  • classes/types
  • methods
    • static or class methods start with uppercase.
    • instance methods start with lowercase.
  • Names should NEVER start with Py*_. These names are reserved for Python itself. Suggest using BPy*_ instead.

tp_getset

Use of the tp_getset slot in a PyTypeObject has some advantages.

The plan is to remove existing getter and settter methods and replace them with attribute access.

The values from getting and setting attributes should play nicely together. Assignments like this should work:

objA.attr = objB.attr

degrees vs radians

Angles in trigonometric functions are defined in radians. Degrees are more common in everyday usage. Blender has a mix of both. Using both is confusing. It also violates our principle that attribute access should interoperate.

Once we have a mix of attributes or methods using both radians and degrees, it becomes difficult to write scripts without constantly consulting the documentation for the correct units.

  • IMHO, since consistency is a virtue and math functions use radians, it makes sense use radians throughout our API. The Python math module already has conversion functions for degrees() and radians(). These can be used to present and receive values from the user.
Another possibility is we can follow OpenGL's convention and create methods a based on a specific type. For example, Bone.fooD() uses degrees while Bone.fooR() uses radians. One of these methods is essentially a wrapper for the other. Stivs

Exceptions for Error Handling

Use of exceptions rather than return codes simplifies error handling.

Return values are not overloaded with a mix of objects and error codes.

We can define our own exceptions and error strings as needed.

This is a list of Standard Python Exceptions

Common errors and the exceptions they raise:

  • Accessing a non-existent dictionary key will raise a KeyError exception.
  • Searching a list for a non-existent value will raise a ValueError exception.
  • Calling a non-existent method will raise an AttributeError exception.
  • Referencing a non-existent variable will raise a NameError exception.
  • Mixing datatypes without coercion will raise a TypeError exception.
note: excerpted from Dive into Python

use of doxygen

No one would accuse us of having over-documented the Bpy source code. Doxygen is a markup language for adding comments to source code that can be processed into pretty html

Code Organization

Where to put new code?

  • create a new directory or directory hierarchy?
  • use cvs branch?

Module organization

  • Flatten module/class hierarchy?
  • Create more submodules ?

User Documentation

  • continue use of epydoc?
    • epydoc markup converts to html for online docs
  • simply use docstrings in C source?
    • docstrings in the source show up in the interpreter - good
    • writing long or complex examples as C strings is a pain. - bad
  • maintain user doc in mediawiki format on blender wiki?

Testing

  • how and what
  • everything?

- memory management tests would be nice: would it be easy to write some sort of stress tests of e.g. Mathutils funcs (which have had leaks?) to test for mem usage?

- basic operations, like: ob = Blender.cur_scene.active_object; assert isinstance(Blender.Object, ob)

basically after the API is drafted, we could write complete tests for it in py. the tests will first break, but when the cleanup is complpete, they pass :) ~antont

API Requests

Misc notes...

  • Will we maintain NMesh? (seems like a good time to get rid of it)
  • Remove NMesh.PutRaw() - because it allows the programmer to be unaware of context and is too easy to everwrite existing data. Add to the scene instead by linking to a new object.
  • ob.link(data), replace with... ob.data = data
  • ob.sel = 1 - Will not make the object active. Rather scn.activeObject = ob
  • Will we keep the Module Get() functions?, Scene.Get('somescene') and Scene.Get() for a list?

http://mediawiki.blender.org/index.php/BPy_API_Cleanup_-_2006