Quellcode durchsuchen

PEP8 formatting and cleanup on the root exporter package (pylint was not happy)
this does not cover the scope of the api/ package

repsac vor 10 Jahren
Ursprung
Commit
ae907ebbc9

+ 284 - 176
utils/exporters/blender/addons/io_three/__init__.py

@@ -39,132 +39,177 @@ SETTINGS_FILE_EXPORT = 'three_settings_export.js'
 
 
 bl_info = {
-    'name': 'Three.js Format',
-    'author': 'repsac, mrdoob, yomotsu, mpk, jpweeks',
+    'name': "Three.js Format",
+    'author': "repsac, mrdoob, yomotsu, mpk, jpweeks",
     'version': (1, 2, 1),
     'blender': (2, 7, 3),
-    'location': 'File > Import-Export',
-    'description': 'Export Three.js formatted JSON files.',
-    'warning': '',
-    'wiki_url': 'https://github.com/mrdoob/three.js/tree/'\
-        'master/utils/exporters/blender',
-    'tracker_url':  'https://github.com/mrdoob/three.js/issues',
+    'location': "File > Import-Export",
+    'description': "Export Three.js formatted JSON files.",
+    'warning': "Importer not included.",
+    'wiki_url': "https://github.com/mrdoob/three.js/tree/"\
+        "master/utils/exporters/blender",
+    'tracker_url':  "https://github.com/mrdoob/three.js/issues",
     'category': 'Import-Export'
 }
 
 def _geometry_types():
-    types = [
-        (constants.GLOBAL, constants.GLOBAL.title(), 
-        constants.GLOBAL),
-        (constants.GEOMETRY, constants.GEOMETRY.title(), 
-        constants.GEOMETRY),
-        (constants.BUFFER_GEOMETRY, constants.BUFFER_GEOMETRY, 
-        constants.BUFFER_GEOMETRY),
-    ]
+    """The valid geometry types that are supported by Three.js
+
+    :return: list of tuples
+
+    """
+    keys = (constants.GLOBAL,
+            constants.GEOMETRY,
+            constants.BUFFER_GEOMETRY)
+    types = []
+    for key in keys:
+        types.append((key, key.title(), key))
 
     return types
 
 bpy.types.Mesh.THREE_geometry_type = EnumProperty(
-    name='Geometry type',
-    description='Geometry type',
+    name="Geometry type",
+    description="Geometry type",
     items=_geometry_types(),
     default=constants.GLOBAL)
 
-class MESH_PT_hello(bpy.types.Panel):
+class ThreeMesh(bpy.types.Panel):
+    """Creates custom properties on a mesh node"""
 
     bl_label = 'THREE'
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
     bl_context = 'data'
-    
+
     def draw(self, context):
+        """
+
+        :param context:
+
+        """
         row = self.layout.row()
         if context.mesh:
-            row.prop(context.mesh, 'THREE_geometry_type', text='Type')
+            row.prop(context.mesh,
+                     'THREE_geometry_type',
+                     text="Type")
 
 def _blending_types(index):
-    types = (
-        constants.BLENDING_TYPES.NONE, 
-        constants.BLENDING_TYPES.NORMAL, 
-        constants.BLENDING_TYPES.ADDITIVE, 
-        constants.BLENDING_TYPES.SUBTRACTIVE, 
-        constants.BLENDING_TYPES.MULTIPLY, 
-        constants.BLENDING_TYPES.CUSTOM)
+    """Supported blending types for Three.js
+
+    :param index:
+    :type index: int
+    :returns: tuple if types (str, str, str)
+
+    """
+    types = (constants.BLENDING_TYPES.NONE,
+             constants.BLENDING_TYPES.NORMAL,
+             constants.BLENDING_TYPES.ADDITIVE,
+             constants.BLENDING_TYPES.SUBTRACTIVE,
+             constants.BLENDING_TYPES.MULTIPLY,
+             constants.BLENDING_TYPES.CUSTOM)
     return (types[index], types[index], types[index])
 
 bpy.types.Material.THREE_blending_type = EnumProperty(
-    name='Blending type', 
-    description='Blending type', 
-    items=[_blending_types(x) for x in range(5)], 
+    name="Blending type",
+    description="Blending type",
+    items=[_blending_types(x) for x in range(5)],
     default=constants.BLENDING_TYPES.NORMAL)
 
 bpy.types.Material.THREE_depth_write = BoolProperty(default=True)
 bpy.types.Material.THREE_depth_test = BoolProperty(default=True)
 
-class MATERIAL_PT_hello(bpy.types.Panel):
+class ThreeMaterial(bpy.types.Panel):
+    """Adds custom properties to the Materials of an object"""
 
     bl_label = 'THREE'
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
     bl_context = 'material'
-    
+
     def draw(self, context):
+        """
+
+        :param context:
+
+        """
         layout = self.layout
         mat = context.material
-    
+
         if mat is not None:
             row = layout.row()
-            row.label(text='Selected material: %s' % mat.name )
+            row.label(text="Selected material: %s" % mat.name)
 
             row = layout.row()
-            row.prop(mat, 'THREE_blending_type', 
-                text='Blending type' )
+            row.prop(mat, 'THREE_blending_type',
+                     text="Blending type")
 
             row = layout.row()
-            row.prop(mat, 'THREE_depth_write', 
-                text='Enable depth writing' )
+            row.prop(mat, 'THREE_depth_write',
+                     text="Enable depth writing")
 
             row = layout.row()
-            row.prop(mat, 'THREE_depth_test', 
-                text='Enable depth testing' )
+            row.prop(mat, 'THREE_depth_test',
+                     text="Enable depth testing")
 
 def _mag_filters(index):
+    """Three.js mag filters
+
+    :param index:
+    :type index: int
+    :returns: tuple with the filter values
+
+    """
     types = (constants.LINEAR_FILTERS.LINEAR,
-        constants.NEAREST_FILTERS.NEAREST)
+             constants.NEAREST_FILTERS.NEAREST)
     return (types[index], types[index], types[index])
 
 bpy.types.Texture.THREE_mag_filter = EnumProperty(
-    name='Mag Filter',
-    items = [_mag_filters(x) for x in range(2)],
+    name="Mag Filter",
+    items=[_mag_filters(x) for x in range(2)],
     default=constants.LINEAR_FILTERS.LINEAR)
 
 def _min_filters(index):
+    """Three.js min filters
+
+    :param index:
+    :type index: int
+    :returns: tuple with the filter values
+
+    """
     types = (constants.LINEAR_FILTERS.LINEAR,
-        constants.LINEAR_FILTERS.MIP_MAP_NEAREST,
-        constants.LINEAR_FILTERS.MIP_MAP_LINEAR,
-        constants.NEAREST_FILTERS.NEAREST,
-        constants.NEAREST_FILTERS.MIP_MAP_NEAREST,
-        constants.NEAREST_FILTERS.MIP_MAP_LINEAR)
+             constants.LINEAR_FILTERS.MIP_MAP_NEAREST,
+             constants.LINEAR_FILTERS.MIP_MAP_LINEAR,
+             constants.NEAREST_FILTERS.NEAREST,
+             constants.NEAREST_FILTERS.MIP_MAP_NEAREST,
+             constants.NEAREST_FILTERS.MIP_MAP_LINEAR)
     return (types[index], types[index], types[index])
 
 bpy.types.Texture.THREE_min_filter = EnumProperty(
-    name='Min Filter',
-    items = [_min_filters(x) for x in range(6)],
+    name="Min Filter",
+    items=[_min_filters(x) for x in range(6)],
     default=constants.LINEAR_FILTERS.MIP_MAP_LINEAR)
 
 def _mapping(index):
+    """Three.js texture mappings types
+
+    :param index:
+    :type index: int
+    :returns: tuple with the mapping values
+
+    """
     types = (constants.MAPPING_TYPES.UV,
-        constants.MAPPING_TYPES.CUBE_REFLECTION,
-        constants.MAPPING_TYPES.CUBE_REFRACTION,
-        constants.MAPPING_TYPES.SPHERICAL_REFLECTION)
+             constants.MAPPING_TYPES.CUBE_REFLECTION,
+             constants.MAPPING_TYPES.CUBE_REFRACTION,
+             constants.MAPPING_TYPES.SPHERICAL_REFLECTION)
     return (types[index], types[index], types[index])
 
 bpy.types.Texture.THREE_mapping = EnumProperty(
-    name='Mapping',
-    items = [_mapping(x) for x in range(4)],
+    name="Mapping",
+    items=[_mapping(x) for x in range(4)],
     default=constants.MAPPING_TYPES.UV)
 
-class TEXTURE_PT_hello(bpy.types.Panel):
+class ThreeTexture(bpy.types.Panel):
+    """Adds custom properties to a texture"""
     bl_label = 'THREE'
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -172,28 +217,39 @@ class TEXTURE_PT_hello(bpy.types.Panel):
 
     #@TODO: possible to make cycles compatible?
     def draw(self, context):
+        """
+
+        :param context:
+
+        """
         layout = self.layout
         tex = context.texture
 
         if tex is not None:
             row = layout.row()
-            row.prop(tex, 'THREE_mapping', text='Mapping')
+            row.prop(tex, 'THREE_mapping', text="Mapping")
 
             row = layout.row()
-            row.prop(tex, 'THREE_mag_filter', text='Mag Filter')
+            row.prop(tex, 'THREE_mag_filter', text="Mag Filter")
 
             row = layout.row()
-            row.prop(tex, 'THREE_min_filter', text='Min Filter')
+            row.prop(tex, 'THREE_min_filter', text="Min Filter")
 
 bpy.types.Object.THREE_export = bpy.props.BoolProperty(default=True)
 
-class OBJECT_PT_hello(bpy.types.Panel):
+class ThreeObject(bpy.types.Panel):
+    """Adds custom properties to an object"""
     bl_label = 'THREE'
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
     bl_context = 'object'
 
     def draw(self, context):
+        """
+
+        :param context:
+
+        """
         layout = self.layout
         obj = context.object
 
@@ -201,11 +257,22 @@ class OBJECT_PT_hello(bpy.types.Panel):
         row.prop(obj, 'THREE_export', text='Export')
 
 def get_settings_fullpath():
+    """
+
+    :returns: Full path to the settings file (temp directory)
+
+    """
     return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
 
 
 def save_settings_export(properties):
+    """Save the current export settings to disk.
+
+    :param properties:
+    :returns: settings
+    :rtype: dict
 
+    """
     settings = {
         constants.VERTICES: properties.option_vertices,
         constants.FACES: properties.option_faces,
@@ -243,7 +310,7 @@ def save_settings_export(properties):
     }
 
     fname = get_settings_fullpath()
-    logging.debug('Saving settings to %s', fname)
+    logging.debug("Saving settings to %s", fname)
     with open(fname, 'w') as stream:
         json.dump(settings, stream)
 
@@ -251,35 +318,42 @@ def save_settings_export(properties):
 
 
 def restore_settings_export(properties):
+    """Restore the settings (if settings file is found on disk)
+    If not found thend default to paramgers defined in
+    constants.EXPORT_OPTIONS
+
+    :param properties:
+
+    """
 
     settings = {}
 
     fname = get_settings_fullpath()
     if os.path.exists(fname) and os.access(fname, os.R_OK):
-        logging.debug('Settings cache found %s', fname)
+        logging.debug("Settings cache found %s", fname)
         with open(fname, 'r') as fs:
             settings = json.load(fs)
     else:
-        logging.debug('No settings file found, using defaults.')
+        logging.debug("No settings file found, using defaults.")
 
     ## Geometry {
     properties.option_vertices = settings.get(
-        constants.VERTICES, 
+        constants.VERTICES,
         constants.EXPORT_OPTIONS[constants.VERTICES])
 
     properties.option_faces = settings.get(
-        constants.FACES, 
+        constants.FACES,
         constants.EXPORT_OPTIONS[constants.FACES])
     properties.option_normals = settings.get(
-        constants.NORMALS, 
+        constants.NORMALS,
         constants.EXPORT_OPTIONS[constants.NORMALS])
 
     properties.option_skinning = settings.get(
-        constants.SKINNING, 
+        constants.SKINNING,
         constants.EXPORT_OPTIONS[constants.SKINNING])
 
     properties.option_bones = settings.get(
-        constants.BONES, 
+        constants.BONES,
         constants.EXPORT_OPTIONS[constants.BONES])
 
     properties.option_influences = settings.get(
@@ -293,49 +367,49 @@ def restore_settings_export(properties):
 
     ## Materials {
     properties.option_materials = settings.get(
-        constants.MATERIALS, 
+        constants.MATERIALS,
         constants.EXPORT_OPTIONS[constants.MATERIALS])
 
     properties.option_uv_coords = settings.get(
-        constants.UVS, 
+        constants.UVS,
         constants.EXPORT_OPTIONS[constants.UVS])
 
     properties.option_face_materials = settings.get(
-        constants.FACE_MATERIALS, 
+        constants.FACE_MATERIALS,
         constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
 
     properties.option_maps = settings.get(
-        constants.MAPS, 
+        constants.MAPS,
         constants.EXPORT_OPTIONS[constants.MAPS])
 
     properties.option_colors = settings.get(
-        constants.COLORS, 
+        constants.COLORS,
         constants.EXPORT_OPTIONS[constants.COLORS])
 
     properties.option_mix_colors = settings.get(
-        constants.MIX_COLORS, 
+        constants.MIX_COLORS,
         constants.EXPORT_OPTIONS[constants.MIX_COLORS])
     ## }
 
     ## Settings {
     properties.option_scale = settings.get(
-        constants.SCALE, 
+        constants.SCALE,
         constants.EXPORT_OPTIONS[constants.SCALE])
 
     properties.option_round_off = settings.get(
-        constants.ENABLE_PRECISION, 
+        constants.ENABLE_PRECISION,
         constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
 
     properties.option_round_value = settings.get(
-        constants.PRECISION, 
+        constants.PRECISION,
         constants.EXPORT_OPTIONS[constants.PRECISION])
 
     properties.option_logging = settings.get(
-        constants.LOGGING, 
+        constants.LOGGING,
         constants.EXPORT_OPTIONS[constants.LOGGING])
 
     properties.option_compression = settings.get(
-        constants.COMPRESSION, 
+        constants.COMPRESSION,
         constants.NONE)
 
     properties.option_indent = settings.get(
@@ -343,43 +417,43 @@ def restore_settings_export(properties):
         constants.EXPORT_OPTIONS[constants.INDENT])
 
     properties.option_copy_textures = settings.get(
-        constants.COPY_TEXTURES, 
+        constants.COPY_TEXTURES,
         constants.EXPORT_OPTIONS[constants.COPY_TEXTURES])
 
     properties.option_embed_animation = settings.get(
-        constants.EMBED_ANIMATION, 
+        constants.EMBED_ANIMATION,
         constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
     ## }
 
     ## Scene {
     properties.option_export_scene = settings.get(
-        constants.SCENE, 
+        constants.SCENE,
         constants.EXPORT_OPTIONS[constants.SCENE])
 
     #properties.option_embed_geometry = settings.get(
-    #    constants.EMBED_GEOMETRY, 
+    #    constants.EMBED_GEOMETRY,
     #    constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
 
     properties.option_lights = settings.get(
-        constants.LIGHTS, 
+        constants.LIGHTS,
         constants.EXPORT_OPTIONS[constants.LIGHTS])
 
     properties.option_cameras = settings.get(
-        constants.CAMERAS, 
+        constants.CAMERAS,
         constants.EXPORT_OPTIONS[constants.CAMERAS])
     ## }
 
     ## Animation {
     properties.option_animation_morph = settings.get(
-        constants.MORPH_TARGETS, 
+        constants.MORPH_TARGETS,
         constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
 
     properties.option_animation_skeletal = settings.get(
-        constants.ANIMATION, 
+        constants.ANIMATION,
         constants.EXPORT_OPTIONS[constants.ANIMATION])
 
     properties.option_frame_step = settings.get(
-        constants.FRAME_STEP, 
+        constants.FRAME_STEP,
         constants.EXPORT_OPTIONS[constants.FRAME_STEP])
 
     properties.option_frame_index_as_time = settings.get(
@@ -388,18 +462,28 @@ def restore_settings_export(properties):
     ## }
 
 def compression_types():
+    """Supported compression formats
+
+    :rtype: tuple
+
+    """
     types = [(constants.NONE, constants.NONE, constants.NONE)]
 
     try:
         import msgpack
-        types.append((constants.MSGPACK, constants.MSGPACK, 
-            constants.MSGPACK))
+        types.append((constants.MSGPACK, constants.MSGPACK,
+                      constants.MSGPACK))
     except ImportError:
         pass
 
     return types
 
 def animation_options():
+    """The supported skeletal animation types
+
+    :returns: list of tuples
+
+    """
     anim = [
         (constants.OFF, constants.OFF.title(), constants.OFF),
         (constants.POSE, constants.POSE.title(), constants.POSE),
@@ -409,86 +493,87 @@ def animation_options():
     return anim
 
 class ExportThree(bpy.types.Operator, ExportHelper):
+    """Class that handles the export properties"""
 
-    bl_idname='export.three'
+    bl_idname = 'export.three'
     bl_label = 'Export THREE'
 
     filename_ext = constants.EXTENSION
 
     option_vertices = BoolProperty(
-        name='Vertices', 
-        description='Export vertices', 
+        name="Vertices",
+        description="Export vertices",
         default=constants.EXPORT_OPTIONS[constants.VERTICES])
 
     option_faces = BoolProperty(
-        name='Faces', 
-        description='Export faces', 
+        name="Faces",
+        description="Export faces",
         default=constants.EXPORT_OPTIONS[constants.FACES])
 
     option_normals = BoolProperty(
-        name='Normals', 
-        description='Export normals', 
+        name="Normals",
+        description="Export normals",
         default=constants.EXPORT_OPTIONS[constants.NORMALS])
 
     option_colors = BoolProperty(
-        name='Vertex Colors', 
-        description='Export vertex colors', 
+        name="Vertex Colors",
+        description="Export vertex colors",
         default=constants.EXPORT_OPTIONS[constants.COLORS])
 
     option_mix_colors = BoolProperty(
-        name='Mix Colors',
-        description='Mix material and vertex colors',
+        name="Mix Colors",
+        description="Mix material and vertex colors",
         default=constants.EXPORT_OPTIONS[constants.MIX_COLORS])
 
     option_uv_coords = BoolProperty(
-        name='UVs', 
-        description='Export texture coordinates', 
+        name="UVs",
+        description="Export texture coordinates",
         default=constants.EXPORT_OPTIONS[constants.UVS])
 
     option_materials = BoolProperty(
-        name='Materials', 
-        description='Export materials', 
+        name="Materials",
+        description="Export materials",
         default=constants.EXPORT_OPTIONS[constants.MATERIALS])
 
     option_face_materials = BoolProperty(
-        name='Face Materials',
-        description='Face mapping materials',
+        name="Face Materials",
+        description="Face mapping materials",
         default=constants.EXPORT_OPTIONS[constants.FACE_MATERIALS])
 
     option_maps = BoolProperty(
-        name='Textures',
-        description='Include texture maps',
+        name="Textures",
+        description="Include texture maps",
         default=constants.EXPORT_OPTIONS[constants.MAPS])
 
     option_skinning = BoolProperty(
-        name='Skinning', 
-        description='Export skin data', 
+        name="Skinning",
+        description="Export skin data",
         default=constants.EXPORT_OPTIONS[constants.SKINNING])
 
     option_bones = BoolProperty(
-        name='Bones', 
-        description='Export bones', 
+        name="Bones",
+        description="Export bones",
         default=constants.EXPORT_OPTIONS[constants.BONES])
 
     option_scale = FloatProperty(
-        name='Scale', 
-        description='Scale vertices', 
-        min=0.01, 
-        max=1000.0, 
-        soft_min=0.01, 
-        soft_max=1000.0, 
+        name="Scale",
+        description="Scale vertices",
+        min=0.01,
+        max=1000.0,
+        soft_min=0.01,
+        soft_max=1000.0,
         default=constants.EXPORT_OPTIONS[constants.SCALE])
 
     option_round_off = BoolProperty(
-        name='Enable Precision',
-        description='Round off floating point values',
+        name="Enable Precision",
+        description="Round off floating point values",
         default=constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION])
 
     option_round_value = IntProperty(
-        name='Precision',
+        name="Precision",
         min=0,
         max=16,
-        description='Floating point precision',
+        description="Floating point precision",
         default=constants.EXPORT_OPTIONS[constants.PRECISION])
 
     logging_types = [
@@ -499,88 +584,88 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         (constants.CRITICAL, constants.CRITICAL, constants.CRITICAL)]
 
     option_logging = EnumProperty(
-        name='', 
-        description = 'Logging verbosity level', 
-        items=logging_types, 
+        name="",
+        description="Logging verbosity level",
+        items=logging_types,
         default=constants.DEBUG)
 
     option_geometry_type = EnumProperty(
-        name='Type',
-        description='Geometry type',
+        name="Type",
+        description="Geometry type",
         items=_geometry_types()[1:],
         default=constants.GEOMETRY)
 
     option_export_scene = BoolProperty(
-        name='Scene', 
-        description='Export scene', 
+        name="Scene",
+        description="Export scene",
         default=constants.EXPORT_OPTIONS[constants.SCENE])
-    
+
     #@TODO: removing this option since the ObjectLoader doesn't have
     #       support for handling external geometry data
     #option_embed_geometry = BoolProperty(
-    #    name='Embed geometry', 
-    #    description='Embed geometry', 
+    #    name="Embed geometry",
+    #    description="Embed geometry",
     #    default=constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY])
 
     option_embed_animation = BoolProperty(
-        name='Embed animation', 
-        description='Embed animation data with the geometry data', 
+        name="Embed animation",
+        description="Embed animation data with the geometry data",
         default=constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION])
 
     option_copy_textures = BoolProperty(
-        name='Copy textures', 
-        description='Copy textures', 
+        name="Copy textures",
+        description="Copy textures",
         default=constants.EXPORT_OPTIONS[constants.COPY_TEXTURES])
 
     option_lights = BoolProperty(
-        name='Lights', 
-        description='Export default scene lights', 
+        name="Lights",
+        description="Export default scene lights",
         default=False)
 
     option_cameras = BoolProperty(
-        name='Cameras', 
-        description='Export default scene cameras', 
+        name="Cameras",
+        description="Export default scene cameras",
         default=False)
 
     option_animation_morph = BoolProperty(
-        name='Morph animation', 
-        description='Export animation (morphs)', 
+        name="Morph animation",
+        description="Export animation (morphs)",
         default=constants.EXPORT_OPTIONS[constants.MORPH_TARGETS])
 
     option_animation_skeletal = EnumProperty(
-        name='', 
-        description='Export animation (skeletal)', 
+        name="",
+        description="Export animation (skeletal)",
         items=animation_options(),
         default=constants.OFF)
 
     option_frame_index_as_time = BoolProperty(
-        name='Frame index as time',
-        description='Use (original) frame index as frame time',
+        name="Frame index as time",
+        description="Use (original) frame index as frame time",
         default=constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
 
     option_frame_step = IntProperty(
-        name='Frame step', 
-        description='Animation frame step', 
-        min=1, 
-        max=1000, 
-        soft_min=1, 
-        soft_max=1000, 
+        name="Frame step",
+        description="Animation frame step",
+        min=1,
+        max=1000,
+        soft_min=1,
+        soft_max=1000,
         default=1)
- 
+
     option_indent = BoolProperty(
-        name='Indent JSON',
-        description='Disable this to reduce the file size',
+        name="Indent JSON",
+        description="Disable this to reduce the file size",
         default=constants.EXPORT_OPTIONS[constants.INDENT])
 
     option_compression = EnumProperty(
-        name='', 
-        description = 'Compression options', 
-        items=compression_types(), 
+        name="",
+        description="Compression options",
+        items=compression_types(),
         default=constants.NONE)
 
     option_influences = IntProperty(
-        name='Influences',
-        description='Maximum number of bone influences',
+        name="Influences",
+        description="Maximum number of bone influences",
         min=1,
         max=4,
         default=2)
@@ -591,17 +676,27 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
     @classmethod
     def poll(cls, context):
+        """
+
+        :param context:
+
+        """
         return context.active_object is not None
 
     def execute(self, context):
+        """
+
+        :param context:
+
+        """
         if not self.properties.filepath:
-            raise Exception('filename not set')
+            raise Exception("filename not set")
 
         settings = save_settings_export(self.properties)
 
         filepath = self.filepath
         if settings[constants.COMPRESSION] == constants.MSGPACK:
-            filepath = '%s%s' % (filepath[:-4], constants.PACK)
+            filepath = "%s%s" % (filepath[:-4], constants.PACK)
 
         from io_three import exporter
         if settings[constants.SCENE]:
@@ -612,11 +707,16 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         return {'FINISHED'}
 
     def draw(self, context):
+        """
+
+        :param context:
+
+        """
         layout = self.layout
 
         ## Geometry {
         row = layout.row()
-        row.label(text='GEOMETRY:')
+        row.label(text="GEOMETRY:")
 
         row = layout.row()
         row.prop(self.properties, 'option_vertices')
@@ -639,7 +739,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         ## Materials {
         row = layout.row()
-        row.label(text='- Shading:')
+        row.label(text="- Shading:")
 
         row = layout.row()
         row.prop(self.properties, 'option_face_materials')
@@ -650,18 +750,18 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         row = layout.row()
         row.prop(self.properties, 'option_mix_colors')
         ## }
-    
+
         layout.separator()
 
         ## Animation {
         row = layout.row()
-        row.label(text='- Animation:')
+        row.label(text="- Animation:")
 
         row = layout.row()
         row.prop(self.properties, 'option_animation_morph')
 
         row = layout.row()
-        row.label(text='Skeletal animations:')
+        row.label(text="Skeletal animations:")
 
         row = layout.row()
         row.prop(self.properties, 'option_animation_skeletal')
@@ -685,7 +785,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         ## Scene {
         row = layout.row()
-        row.label(text='SCENE:')
+        row.label(text="SCENE:")
 
         row = layout.row()
         row.prop(self.properties, 'option_export_scene')
@@ -703,7 +803,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         ## Settings {
         row = layout.row()
-        row.label(text='SETTINGS:')
+        row.label(text="SETTINGS:")
 
         row = layout.row()
         row.prop(self.properties, 'option_maps')
@@ -713,7 +813,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         row = layout.row()
         row.prop(self.properties, 'option_scale')
-        
+
         layout.row()
         row = layout.row()
         row.prop(self.properties, 'option_round_off')
@@ -722,13 +822,13 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
         layout.row()
         row = layout.row()
-        row.label(text='Logging verbosity:')
+        row.label(text="Logging verbosity:")
 
         row = layout.row()
         row.prop(self.properties, 'option_logging')
 
         row = layout.row()
-        row.label(text='File compression format:')
+        row.label(text="File compression format:")
 
         row = layout.row()
         row.prop(self.properties, 'option_compression')
@@ -740,21 +840,29 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
 
 def menu_func_export(self, context):
+    """
+
+    :param self:
+    :param context:
+
+    """
     default_path = bpy.data.filepath.replace('.blend', constants.EXTENSION)
-    text = 'Three.js (%s)' % constants.EXTENSION
+    text = "Three.js (%s)" % constants.EXTENSION
     operator = self.layout.operator(ExportThree.bl_idname, text=text)
     operator.filepath = default_path
 
 
 def register():
+    """Registers the addon (Blender boilerplate)"""
     bpy.utils.register_module(__name__)
     bpy.types.INFO_MT_file_export.append(menu_func_export)
 
 
 def unregister():
+    """Unregisters the addon (Blender boilerplate)"""
     bpy.utils.unregister_module(__name__)
     bpy.types.INFO_MT_file_export.remove(menu_func_export)
 
 
 if __name__ == '__main__':
-    register() 
+    register()

+ 66 - 19
utils/exporters/blender/addons/io_three/exporter/base_classes.py

@@ -1,40 +1,68 @@
 from . import utilities
-from .. import constants, exceptions 
+from .. import constants, exceptions
 
 
 class BaseClass(constants.BASE_DICT):
+    """Base class which inherits from a base dictionary object."""
     _defaults = {}
 
     def __init__(self, parent=None, type=None):
         constants.BASE_DICT.__init__(self)
 
-        self.__type = type
+        self._type = type
 
-        self.__parent = parent
+        self._parent = parent
 
         constants.BASE_DICT.update(self, self._defaults.copy())
-     
+
     def __setitem__(self, key, value):
         if not isinstance(value, constants.VALID_DATA_TYPES):
-            msg = 'Value is an invalid data type: %s' % type(value)
-            raise exceptions.ThreeValueError(msg) 
+            msg = "Value is an invalid data type: %s" % type(value)
+            raise exceptions.ThreeValueError(msg)
         constants.BASE_DICT.__setitem__(self, key, value)
 
     @property
     def count(self):
+        """
+
+        :return: number of keys
+        :rtype: int
+
+        """
         return len(self.keys())
 
     @property
     def parent(self):
-        return self.__parent
+        """
+
+        :return: parent object
+
+        """
+        return self._parent
 
     @property
     def type(self):
-        return self.__type
-    
+        """
+
+        :return: the type (if applicable)
+
+        """
+        return self._type
+
     def copy(self):
+        """Copies the items to a standard dictionary object.
+
+        :rtype: dict
+
+        """
         data = {}
         def _dict_copy(old, new):
+            """Recursive function for processing all values
+
+            :param old:
+            :param new:
+
+            """
             for key, value in old.items():
                 if isinstance(value, (str, list)):
                     new[key] = value[:]
@@ -51,10 +79,11 @@ class BaseClass(constants.BASE_DICT):
         return data
 
 
-class BaseNode(BaseClass):  
+class BaseNode(BaseClass):
+    """Base class for all nodes for the current platform."""
     def __init__(self, node, parent, type):
         BaseClass.__init__(self, parent=parent, type=type)
-        self.__node = node
+        self._node = node
         if node is None:
             self[constants.UUID] = utilities.id()
         else:
@@ -68,33 +97,51 @@ class BaseNode(BaseClass):
         else:
             scene = None
 
-        self.__scene = scene
- 
+        self._scene = scene
+
     @property
     def node(self):
-        return self.__node
+        """
+
+        :return: name of the node
+
+        """
+        return self._node
 
     @property
     def scene(self):
-        return self.__scene
+        """
+
+        :return: returns the scene point
+
+        """
+
+        return self._scene
 
     @property
     def options(self):
+        """
+
+        :return: export options
+        :retype: dict
+
+        """
         return self.scene.options
 
 
 class BaseScene(BaseClass):
+    """Base class that scenes inherit from."""
     def __init__(self, filepath, options):
         BaseClass.__init__(self, type=constants.SCENE)
 
-        self.__filepath = filepath
+        self._filepath = filepath
 
-        self.__options = options.copy()
+        self._options = options.copy()
 
     @property
     def filepath(self):
-        return self.__filepath
+        return self._filepath
 
     @property
     def options(self):
-        return self.__options
+        return self._options

+ 148 - 76
utils/exporters/blender/addons/io_three/exporter/geometry.py

@@ -7,9 +7,10 @@ FORMAT_VERSION = 3
 
 
 class Geometry(base_classes.BaseNode):
+    """Class that wraps a single mesh/geometry node."""
     def __init__(self, node, parent=None):
-        logger.debug('Geometry().__init__(%s)', node)
-        
+        logger.debug("Geometry().__init__(%s)", node)
+
         #@TODO: maybe better to have `three` constants for
         #       strings that are specific to `three` properties
         geo_type = constants.GEOMETRY.title()
@@ -18,23 +19,28 @@ class Geometry(base_classes.BaseNode):
             if opt_type == constants.BUFFER_GEOMETRY:
                 geo_type = constants.BUFFER_GEOMETRY
             elif opt_type != constants.GEOMETRY:
-                logger.error('Unknown geometry type %s', opt_type)
+                logger.error("Unknown geometry type %s", opt_type)
 
-        logger.info('Setting %s to "%s"', node, geo_type)
+        logger.info("Setting %s to '%s'", node, geo_type)
 
         self._defaults[constants.TYPE] = geo_type
-        base_classes.BaseNode.__init__(self, node, 
-            parent=parent,
-            type=geo_type)
+        base_classes.BaseNode.__init__(self, node,
+                                       parent=parent,
+                                       type=geo_type)
 
     @property
     def animation_filename(self):
+        """Calculate the file name for the animation file
+
+        :return: base name for the file
+        """
         compression = self.options.get(constants.COMPRESSION)
         if compression in (None, constants.NONE):
             ext = constants.JSON
         elif compression == constants.MSGPACK:
             ext = constants.PACK
 
+        key = ''
         for key in (constants.MORPH_TARGETS, constants.ANIMATION):
             try:
                 self[key]
@@ -42,27 +48,32 @@ class Geometry(base_classes.BaseNode):
             except KeyError:
                 pass
         else:
-            logger.info('%s has no animation data', self.node)
+            logger.info("%s has no animation data", self.node)
             return
 
         return '%s.%s.%s' % (self.node, key, ext)
 
     @property
     def face_count(self):
+        """Parse the bit masks of the `faces` array.
+
+        :rtype: int
+
+        """
         try:
             faces = self[constants.FACES]
         except KeyError:
-            logger.debug('No parsed faces found')
+            logger.debug("No parsed faces found")
             return 0
 
         length = len(faces)
         offset = 0
-        bitset = lambda x,y: x & ( 1 << y )
+        bitset = lambda x, y: x & (1 << y)
         face_count = 0
 
         masks = (constants.MASK[constants.UVS],
-            constants.MASK[constants.NORMALS],
-            constants.MASK[constants.COLORS])
+                 constants.MASK[constants.NORMALS],
+                 constants.MASK[constants.COLORS])
 
         while offset < length:
             bit = faces[offset]
@@ -84,20 +95,32 @@ class Geometry(base_classes.BaseNode):
 
     @property
     def metadata(self):
+        """Metadata for the current node.
+
+        :rtype: dict
+
+        """
         metadata = {
             constants.GENERATOR: constants.THREE,
             constants.VERSION: FORMAT_VERSION
         }
 
         if self[constants.TYPE] == constants.GEOMETRY.title():
-            self.__geometry_metadata(metadata)
+            self._geometry_metadata(metadata)
         else:
-            self.__buffer_geometry_metadata(metadata)
+            self._buffer_geometry_metadata(metadata)
 
         return metadata
 
     def copy(self, scene=True):
-        logger.debug('Geometry().copy(scene=%s)', scene)
+        """Copy the geometry definitions to a standard dictionary.
+
+        :param scene: toggle for scene formatting (Default = True)
+        :type scene: bool
+        :rtype: dict
+
+        """
+        logger.debug("Geometry().copy(scene=%s)", scene)
         dispatch = {
             True: self._scene_format,
             False: self._geometry_format
@@ -107,47 +130,68 @@ class Geometry(base_classes.BaseNode):
         try:
             data[constants.MATERIALS] = self[constants.MATERIALS].copy()
         except KeyError:
-            logger.debug('No materials to copy')
+            logger.debug("No materials to copy")
 
         return data
 
     def copy_textures(self):
-        logger.debug('Geometry().copy_textures()')
+        """Copy the textures to the destination directory."""
+        logger.debug("Geometry().copy_textures()")
         if self.options.get(constants.COPY_TEXTURES):
             texture_registration = self.register_textures()
             if texture_registration:
-                logger.info('%s has registered textures', self.node)
+                logger.info("%s has registered textures", self.node)
                 io.copy_registered_textures(
                     os.path.dirname(self.scene.filepath),
                     texture_registration)
 
     def parse(self):
-        logger.debug('Geometry().parse()')
+        """Parse the current node"""
+        logger.debug("Geometry().parse()")
         if self[constants.TYPE] == constants.GEOMETRY.title():
-            logger.info('Parsing Geometry format')
-            self.__parse_geometry()
+            logger.info("Parsing Geometry format")
+            self._parse_geometry()
         else:
-            logger.info('Parsing BufferGeometry format')
-            self.__parse_buffer_geometry()
+            logger.info("Parsing BufferGeometry format")
+            self._parse_buffer_geometry()
 
     def register_textures(self):
-        logger.debug('Geometry().register_textures()')
-        return api.mesh.texture_registration(self.node) 
+        """Obtain a texture registration object.
+
+        :rtype: dict
+
+        """
+        logger.debug("Geometry().register_textures()")
+        return api.mesh.texture_registration(self.node)
 
     def write(self, filepath=None):
-        logger.debug('Geometry().write(filepath=%s)', filepath)
+        """Write the geometry definitions to disk. Uses the
+        desitnation path of the scene.
+
+        :param filepath: optional output file path (Default=None)
+        :type filepath: str
+
+        """
+        logger.debug("Geometry().write(filepath=%s)", filepath)
 
         filepath = filepath or self.scene.filepath
 
-        io.dump(filepath, self.copy(scene=False), 
-            options=self.scene.options) 
+        io.dump(filepath, self.copy(scene=False),
+                options=self.scene.options)
 
         if self.options.get(constants.MAPS):
-            logger.info('Copying textures for %s', self.node)
+            logger.info("Copying textures for %s", self.node)
             self.copy_textures()
 
     def write_animation(self, filepath):
-        logger.debug('Geometry().write_animation(%s)', filepath)
+        """Write the animation definitions to a separate file
+        on disk. This helps optimize the geometry file size.
+
+        :param filepath: destination path
+        :type filepath: str
+
+        """
+        logger.debug("Geometry().write_animation(%s)", filepath)
 
         for key in (constants.MORPH_TARGETS, constants.ANIMATION):
             try:
@@ -156,29 +200,35 @@ class Geometry(base_classes.BaseNode):
             except KeyError:
                 pass
         else:
-            logger.info('%s has no animation data', self.node)
+            logger.info("%s has no animation data", self.node)
             return
 
         filepath = os.path.join(filepath, self.animation_filename)
         if filepath:
-            logger.info('Dumping animation data to %s', filepath)
+            logger.info("Dumping animation data to %s", filepath)
             io.dump(filepath, data, options=self.scene.options)
             return filepath
         else:
-            logger.warning('Could not determine a filepath for '\
-                'animation data. Nothing written to disk.')
+            logger.warning("Could not determine a filepath for "\
+                "animation data. Nothing written to disk.")
 
     def _component_data(self):
-        logger.debug('Geometry()._component_data()')
-        
+        """Query the component data only
+
+        :rtype: dict
+
+        """
+        logger.debug("Geometry()._component_data()")
+
         if self[constants.TYPE] != constants.GEOMETRY.title():
             return self[constants.ATTRIBUTES]
 
-        components = [constants.VERTICES, constants.FACES, 
-            constants.UVS, constants.COLORS, constants.NORMALS,
-            constants.BONES, constants.SKIN_WEIGHTS, 
-            constants.SKIN_INDICES, constants.NAME,
-            constants.INFLUENCES_PER_VERTEX]
+        components = [constants.VERTICES, constants.FACES,
+                      constants.UVS, constants.COLORS,
+                      constants.NORMALS, constants.BONES,
+                      constants.SKIN_WEIGHTS,
+                      constants.SKIN_INDICES, constants.NAME,
+                      constants.INFLUENCES_PER_VERTEX]
 
         data = {}
         anim_components = [constants.MORPH_TARGETS, constants.ANIMATION]
@@ -192,20 +242,25 @@ class Geometry(base_classes.BaseNode):
                     pass
                 else:
                     data[component] = os.path.basename(
-                        self.animation_filename) 
+                        self.animation_filename)
+                    break
             else:
-                logger.info('No animation data found for %s', self.node)
+                logger.info("No animation data found for %s", self.node)
 
         for component in components:
             try:
                 data[component] = self[component]
             except KeyError:
-                logger.debug('Component %s not found', component)
-                pass
+                logger.debug("Component %s not found", component)
 
         return data
 
     def _geometry_format(self):
+        """Three.Geometry formatted definitions
+
+        :rtype: dict
+
+        """
         data = self._component_data()
 
         if self[constants.TYPE] != constants.GEOMETRY.title():
@@ -219,17 +274,27 @@ class Geometry(base_classes.BaseNode):
 
         return data
 
-    def __buffer_geometry_metadata(self, metadata):
+    def _buffer_geometry_metadata(self, metadata):
+        """Three.BufferGeometry metadata
+
+        :rtype: dict
+
+        """
         for key, value in self[constants.ATTRIBUTES].items():
             size = value[constants.ITEM_SIZE]
             array = value[constants.ARRAY]
             metadata[key] = len(array)/size
-        
-    def __geometry_metadata(self, metadata): 
+
+    def _geometry_metadata(self, metadata):
+        """Three.Geometry metadat
+
+        :rtype: dict
+
+        """
         skip = (constants.TYPE, constants.FACES, constants.UUID,
-            constants.ANIMATION, constants.SKIN_INDICES,
-            constants.SKIN_WEIGHTS, constants.NAME, 
-            constants.INFLUENCES_PER_VERTEX)
+                constants.ANIMATION, constants.SKIN_INDICES,
+                constants.SKIN_WEIGHTS, constants.NAME,
+                constants.INFLUENCES_PER_VERTEX)
         vectors = (constants.VERTICES, constants.NORMALS)
 
         for key in self.keys():
@@ -249,6 +314,11 @@ class Geometry(base_classes.BaseNode):
             metadata[constants.FACES] = faces
 
     def _scene_format(self):
+        """Format the output for Scene compatability
+
+        :rtype: dict
+
+        """
         data = {
             constants.UUID: self[constants.UUID],
             constants.TYPE: self[constants.TYPE]
@@ -267,34 +337,35 @@ class Geometry(base_classes.BaseNode):
                 }
             else:
                 data[constants.ATTRIBUTES] = component_data
-            data[constants.METADATA] = self.metadata 
+            data[constants.METADATA] = self.metadata
             data[constants.NAME] = self[constants.NAME]
 
-        return data 
+        return data
 
-    def __parse_buffer_geometry(self):
+    def _parse_buffer_geometry(self):
+        """Parse the geometry to Three.BufferGeometry specs"""
         self[constants.ATTRIBUTES] = {}
 
         options_vertices = self.options.get(constants.VERTICES)
         option_normals = self.options.get(constants.NORMALS)
         option_uvs = self.options.get(constants.UVS)
 
-        dispatch = (
-            (constants.POSITION, options_vertices, 
-                api.mesh.buffer_position, 3), 
-            (constants.UV, option_uvs, api.mesh.buffer_uv, 2), 
-            (constants.NORMAL, option_normals, 
-                api.mesh.buffer_normal, 3)
-        )
+        pos_tuple = (constants.POSITION, options_vertices,
+                     api.mesh.buffer_position, 3)
+        uvs_tuple = (constants.UV, option_uvs,
+                     api.mesh.buffer_uv, 2)
+        normals_tuple = (constants.NORMAL, option_normals,
+                         api.mesh.buffer_normal, 3)
+        dispatch = (pos_tuple, uvs_tuple, normals_tuple)
 
-        for key, option, func, size in dispatch: 
+        for key, option, func, size in dispatch:
 
             if not option:
                 continue
 
             array = func(self.node, self.options) or []
-            if not array: 
-                logger.warning('No array could be made for %s', key)
+            if not array:
+                logger.warning("No array could be made for %s", key)
                 continue
 
             self[constants.ATTRIBUTES][key] = {
@@ -303,40 +374,41 @@ class Geometry(base_classes.BaseNode):
                 constants.ARRAY: array
             }
 
-    def __parse_geometry(self):
+    def _parse_geometry(self):
+        """Parse the geometry to Three.Geometry specs"""
         if self.options.get(constants.VERTICES):
-            logger.info('Parsing %s', constants.VERTICES)
+            logger.info("Parsing %s", constants.VERTICES)
             self[constants.VERTICES] = api.mesh.vertices(
                 self.node, self.options) or []
 
         if self.options.get(constants.NORMALS):
-            logger.info('Parsing %s', constants.NORMALS)
+            logger.info("Parsing %s", constants.NORMALS)
             self[constants.NORMALS] = api.mesh.normals(
                 self.node, self.options) or []
 
         if self.options.get(constants.COLORS):
-            logger.info('Parsing %s', constants.COLORS)
+            logger.info("Parsing %s", constants.COLORS)
             self[constants.COLORS] = api.mesh.vertex_colors(
                 self.node) or []
-        
+
         if self.options.get(constants.FACE_MATERIALS):
-            logger.info('Parsing %s', constants.FACE_MATERIALS)
+            logger.info("Parsing %s", constants.FACE_MATERIALS)
             self[constants.MATERIALS] = api.mesh.materials(
                 self.node, self.options) or []
 
         if self.options.get(constants.UVS):
-            logger.info('Parsing %s', constants.UVS)
+            logger.info("Parsing %s", constants.UVS)
             self[constants.UVS] = api.mesh.uvs(
                 self.node, self.options) or []
 
         if self.options.get(constants.FACES):
-            logger.info('Parsing %s', constants.FACES)
+            logger.info("Parsing %s", constants.FACES)
             self[constants.FACES] = api.mesh.faces(
                 self.node, self.options) or []
 
         no_anim = (None, False, constants.OFF)
         if self.options.get(constants.ANIMATION) not in no_anim:
-            logger.info('Parsing %s', constants.ANIMATION)
+            logger.info("Parsing %s", constants.ANIMATION)
             self[constants.ANIMATION] = api.mesh.skeletal_animation(
                 self.node, self.options) or []
 
@@ -345,12 +417,12 @@ class Geometry(base_classes.BaseNode):
 
         bone_map = {}
         if self.options.get(constants.BONES):
-            logger.info('Parsing %s', constants.BONES)
+            logger.info("Parsing %s", constants.BONES)
             bones, bone_map = api.mesh.bones(self.node, self.options)
             self[constants.BONES] = bones
 
         if self.options.get(constants.SKINNING):
-            logger.info('Parsing %s', constants.SKINNING)
+            logger.info("Parsing %s", constants.SKINNING)
             influences = self.options.get(
                 constants.INFLUENCES_PER_VERTEX, 2)
 
@@ -361,7 +433,7 @@ class Geometry(base_classes.BaseNode):
                 self.node, bone_map, influences)
 
         if self.options.get(constants.MORPH_TARGETS):
-            logger.info('Parsing %s', constants.MORPH_TARGETS)
+            logger.info("Parsing %s", constants.MORPH_TARGETS)
             self[constants.MORPH_TARGETS] = api.mesh.morph_targets(
                 self.node, self.options)
 

+ 23 - 2
utils/exporters/blender/addons/io_three/exporter/image.py

@@ -4,22 +4,43 @@ from . import base_classes, io, api
 
 
 class Image(base_classes.BaseNode):
+    """Class the wraps an image node. This is the node that
+    represent that actual file on disk.
+    """
     def __init__(self, node, parent):
-        logger.debug('Image().__init__(%s)', node)
+        logger.debug("Image().__init__(%s)", node)
         base_classes.BaseNode.__init__(self, node, parent, constants.IMAGE)
 
         self[constants.URL] = api.image.file_name(self.node)
 
     @property
     def destination(self):
+        """
+
+        :return: full destination path (when copied)
+
+        """
         dirname = os.path.dirname(self.scene.filepath)
         return os.path.join(dirname, self[constants.URL])
 
     @property
     def filepath(self):
+        """
+
+        :return: source file path
+
+        """
         return api.image.file_path(self.node)
 
     def copy_texture(self, func=io.copy):
-        logger.debug('Image().copy_texture()')
+        """Copy the texture.
+        self.filepath > self.destination
+
+        :param func: Optional function override (Default = io.copy)
+                     arguments are (<source>, <destination>)
+        :return: path the texture was copied to
+
+        """
+        logger.debug("Image().copy_texture()")
         func(self.filepath, self.destination)
         return self.destination

+ 41 - 12
utils/exporters/blender/addons/io_three/exporter/io.py

@@ -5,13 +5,27 @@ from . import _json
 
 
 def copy_registered_textures(dest, registration):
-    logger.debug('io.copy_registered_textures(%s, %s)', dest, registration)
+    """Copy the registered textures to the destination (root) path
+
+    :param dest: destination directory
+    :param registration: registered textures
+    :type dest: str
+    :type registration: dict
+
+    """
+    logger.debug("io.copy_registered_textures(%s, %s)", dest, registration)
     for value in registration.values():
         copy(value['file_path'], dest)
 
 
 def copy(src, dst):
-    logger.debug('io.copy(%s, %s)' % (src, dst))
+    """Copy a file to a destination
+
+    :param src: source file
+    :param dst: destination file/path
+
+    """
+    logger.debug("io.copy(%s, %s)" % (src, dst))
     if os.path.isdir(dst):
         file_name = os.path.basename(src)
         dst = os.path.join(dst, file_name)
@@ -21,19 +35,27 @@ def copy(src, dst):
 
 
 def dump(filepath, data, options=None):
+    """Dump the output to disk (JSON, msgpack, etc)
+
+    :param filepath: output file path
+    :param data: serializable data to write to disk
+    :param options: (Default = None)
+    :type options: dict
+
+    """
     options = options or {}
-    logger.debug('io.dump(%s, data, options=%s)', filepath, options)
+    logger.debug("io.dump(%s, data, options=%s)", filepath, options)
 
     compress = options.get(constants.COMPRESSION, constants.NONE)
     if compress == constants.MSGPACK:
         try:
             import msgpack
         except ImportError:
-            logger.error('msgpack module not found')
+            logger.error("msgpack module not found")
             raise
 
-        logger.info('Dumping to msgpack')
-        func = lambda x,y: msgpack.dump(x, y)
+        logger.info("Dumping to msgpack")
+        func = lambda x, y: msgpack.dump(x, y)
         mode = 'wb'
     else:
         round_off = options.get(constants.ENABLE_PRECISION)
@@ -44,28 +66,35 @@ def dump(filepath, data, options=None):
 
         indent = options.get(constants.INDENT, True)
         indent = 4 if indent else None
-        logger.info('Dumping to JSON')
-        func = lambda x,y: _json.json.dump(x, y, indent=indent)
+        logger.info("Dumping to JSON")
+        func = lambda x, y: _json.json.dump(x, y, indent=indent)
         mode = 'w'
 
-    logger.info('Writing to %s', filepath)
+    logger.info("Writing to %s", filepath)
     with open(filepath, mode=mode) as stream:
         func(data, stream)
 
 
 def load(filepath, options):
-    logger.debug('io.load(%s, %s)', filepath, options)
+    """Load the contents of the file path with the correct parser
+
+    :param filepath: input file path
+    :param options:
+    :type options: dict
+
+    """
+    logger.debug("io.load(%s, %s)", filepath, options)
     compress = options.get(constants.COMPRESSION, constants.NONE)
     if compress == constants.MSGPACK:
         try:
             import msgpack
         except ImportError:
-            logger.error('msgpack module not found')
+            logger.error("msgpack module not found")
             raise
         module = msgpack
         mode = 'rb'
     else:
-        logger.info('Loading JSON')
+        logger.info("Loading JSON")
         module = _json.json
         mode = 'r'
 

+ 27 - 20
utils/exporters/blender/addons/io_three/exporter/material.py

@@ -3,21 +3,23 @@ from . import base_classes, utilities, api
 
 
 class Material(base_classes.BaseNode):
+    """Class that wraps material nodes"""
     def __init__(self, node, parent):
-        logger.debug('Material().__init__(%s)', node)
-        base_classes.BaseNode.__init__(self, node, parent, 
-            constants.MATERIAL)
-        
-        self.__common_attributes()
+        logger.debug("Material().__init__(%s)", node)
+        base_classes.BaseNode.__init__(self, node, parent,
+                                       constants.MATERIAL)
+
+        self._common_attributes()
         if self[constants.TYPE] == constants.THREE_PHONG:
-            self.__phong_attributes()
+            self._phong_attributes()
 
         textures = self.parent.options.get(constants.MAPS)
         if textures:
-            self.__update_maps()
+            self._update_maps()
 
-    def __common_attributes(self):
-        logger.debug('Material().__common_attributes()')
+    def _common_attributes(self):
+        """Parse the common material attributes"""
+        logger.debug('Material()._common_attributes()')
         dispatch = {
             constants.PHONG: constants.THREE_PHONG,
             constants.LAMBERT: constants.THREE_LAMBERT,
@@ -28,7 +30,7 @@ class Material(base_classes.BaseNode):
 
         diffuse = api.material.diffuse_color(self.node)
         self[constants.COLOR] = utilities.rgb2int(diffuse)
-    
+
         if self[constants.TYPE] != constants.THREE_BASIC:
             ambient = api.material.ambient_color(self.node)
             self[constants.AMBIENT] = utilities.rgb2int(ambient)
@@ -45,14 +47,18 @@ class Material(base_classes.BaseNode):
 
         self[constants.DEPTH_WRITE] = api.material.depth_write(self.node)
 
-    def __phong_attributes(self):
-        logger.debug('Material().__phong_attributes()')
+    def _phong_attributes(self):
+        """Parse phong specific attributes"""
+        logger.debug("Material()._phong_attributes()")
         specular = api.material.specular_color(self.node)
         self[constants.SPECULAR] = utilities.rgb2int(specular)
         self[constants.SHININESS] = api.material.specular_coef(self.node)
 
-    def __update_maps(self):
-        logger.debug('Material().__update_maps()')
+    def _update_maps(self):
+        """Parses maps/textures and updates the textures array
+        with any new nodes found.
+        """
+        logger.debug("Material()._update_maps()")
 
         mapping = (
             (api.material.diffuse_map, constants.MAP),
@@ -60,14 +66,14 @@ class Material(base_classes.BaseNode):
             (api.material.light_map, constants.LIGHT_MAP)
         )
 
-        for func,key in mapping:
+        for func, key in mapping:
             map_node = func(self.node)
             if map_node:
                 logger.info('Found map node %s for %s', map_node, key)
                 tex_inst = self.scene.texture(map_node.name)
-                self[key] = tex_inst[constants.UUID] 
+                self[key] = tex_inst[constants.UUID]
 
-        if self[constants.TYPE] ==  constants.THREE_PHONG:
+        if self[constants.TYPE] == constants.THREE_PHONG:
             mapping = (
                 (api.material.bump_map, constants.BUMP_MAP,
                  constants.BUMP_SCALE, api.material.bump_scale),
@@ -77,8 +83,9 @@ class Material(base_classes.BaseNode):
 
             for func, map_key, scale_key, scale_func in mapping:
                 map_node = func(self.node)
-                if not map_node: continue
-                logger.info('Found map node %s for %s', map_node, map_key)
+                if not map_node: 
+                    continue
+                logger.info("Found map node %s for %s", map_node, map_key)
                 tex_inst = self.scene.texture(map_node.name)
-                self[map_key] = tex_inst[constants.UUID] 
+                self[map_key] = tex_inst[constants.UUID]
                 self[scale_key] = scale_func(self.node)

+ 40 - 33
utils/exporters/blender/addons/io_three/exporter/object.py

@@ -3,18 +3,19 @@ from . import base_classes, api
 
 
 class Object(base_classes.BaseNode):
-
+    """Class that wraps an object node"""
     def __init__(self, node, parent=None, type=None):
-        logger.debug('Object().__init__(%s)', node)
+        logger.debug("Object().__init__(%s)", node)
         base_classes.BaseNode.__init__(self, node, parent=parent, type=type)
 
         if self.node:
-            self.__node_setup()
+            self._node_setup()
         else:
-            self.__root_setup()
+            self._root_setup()
 
-    def __init_camera(self):
-        logger.debug('Object().__init_camera()')
+    def _init_camera(self):
+        """Initialize camera attributes"""
+        logger.debug("Object()._init_camera()")
         self[constants.FAR] = api.camera.far(self.node)
         self[constants.NEAR] = api.camera.near(self.node)
 
@@ -29,29 +30,32 @@ class Object(base_classes.BaseNode):
 
     #@TODO: need more light attributes. Some may have to come from
     #       custom blender attributes.
-    def __init_light(self):
-        logger.debug('Object().__init_light()')
+    def _init_light(self):
+        """Initialize light attributes"""
+        logger.debug("Object()._init_light()")
         self[constants.COLOR] = api.light.color(self.node)
         self[constants.INTENSITY] = api.light.intensity(self.node)
 
         if self[constants.TYPE] != constants.DIRECTIONAL_LIGHT:
             self[constants.DISTANCE] = api.light.distance(self.node)
-    
+
         if self[constants.TYPE] == constants.SPOT_LIGHT:
             self[constants.ANGLE] = api.light.angle(self.node)
 
-    def __init_mesh(self):
-        logger.debug('Object().__init_mesh()')
+    def _init_mesh(self):
+        """Initialize mesh attributes"""
+        logger.debug("Object()._init_mesh()")
         mesh = api.object.mesh(self.node, self.options)
         node = self.scene.geometry(mesh)
         if node:
             self[constants.GEOMETRY] = node[constants.UUID]
         else:
-            msg = 'Could not find Geometry() node for %s'
+            msg = "Could not find Geometry() node for %s"
             logger.error(msg, self.node)
 
-    def __node_setup(self):
-        logger.debug('Object().__node_setup()')
+    def _node_setup(self):
+        """Parse common node attributes of all objects"""
+        logger.debug("Object()._node_setup()")
         self[constants.NAME] = api.object.name(self.node)
 
         self[constants.POSITION] = api.object.position(
@@ -68,42 +72,43 @@ class Object(base_classes.BaseNode):
         self[constants.TYPE] = api.object.node_type(self.node)
 
         if self.options.get(constants.MATERIALS):
-            logger.info('Parsing materials for %s', self.node)
+            logger.info("Parsing materials for %s", self.node)
             material_name = api.object.material(self.node)
             if material_name:
-                logger.info('Material found %s', material_name)
+                logger.info("Material found %s", material_name)
                 material_inst = self.scene.material(material_name)
                 self[constants.MATERIAL] = material_inst[constants.UUID]
             else:
-                logger.info('%s has no materials', self.node)
+                logger.info("%s has no materials", self.node)
 
-        casts_shadow = (constants.MESH, 
-            constants.DIRECTIONAL_LIGHT,
-            constants.SPOT_LIGHT)
+        casts_shadow = (constants.MESH,
+                        constants.DIRECTIONAL_LIGHT,
+                        constants.SPOT_LIGHT)
 
         if self[constants.TYPE] in casts_shadow:
-            logger.info('Querying shadow casting for %s', self.node)
+            logger.info("Querying shadow casting for %s", self.node)
             self[constants.CAST_SHADOW] = \
                 api.object.cast_shadow(self.node)
-        
+
         if self[constants.TYPE] == constants.MESH:
-            logger.info('Querying shadow receive for %s', self.node)
+            logger.info("Querying shadow receive for %s", self.node)
             self[constants.RECEIVE_SHADOW] = \
                 api.object.receive_shadow(self.node)
 
         camera = (constants.PERSPECTIVE_CAMERA,
-            constants.ORTHOGRAPHIC_CAMERA)
+                  constants.ORTHOGRAPHIC_CAMERA)
 
-        lights = (constants.AMBIENT_LIGHT, constants.DIRECTIONAL_LIGHT,
-            constants.AREA_LIGHT, constants.POINT_LIGHT, 
-            constants.SPOT_LIGHT, constants.HEMISPHERE_LIGHT)
+        lights = (constants.AMBIENT_LIGHT,
+                  constants.DIRECTIONAL_LIGHT,
+                  constants.AREA_LIGHT, constants.POINT_LIGHT,
+                  constants.SPOT_LIGHT, constants.HEMISPHERE_LIGHT)
 
         if self[constants.TYPE] == constants.MESH:
-            self.__init_mesh()
+            self._init_mesh()
         elif self[constants.TYPE] in camera:
-            self.__init_camera()
+            self._init_camera()
         elif self[constants.TYPE] in lights:
-            self.__init_light()
+            self._init_light()
 
         for child in api.object.children(self.node, self.scene.valid_types):
             if not self.get(constants.CHILDREN):
@@ -111,6 +116,8 @@ class Object(base_classes.BaseNode):
             else:
                 self[constants.CHILDREN].append(Object(child, parent=self))
 
-    def __root_setup(self):
-        logger.debug('Object().__root_setup()')
-        self[constants.MATRIX] = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]
+    def _root_setup(self):
+        """Applies to a root/scene object"""
+        logger.debug("Object()._root_setup()")
+        self[constants.MATRIX] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+                                  1, 0, 0, 0, 0, 1]

+ 113 - 61
utils/exporters/blender/addons/io_three/exporter/scene.py

@@ -4,8 +4,8 @@ from . import (
     base_classes,
     texture,
     material,
-    geometry, 
-    object,
+    geometry,
+    object as object_,
     utilities,
     io,
     api
@@ -13,6 +13,7 @@ from . import (
 
 
 class Scene(base_classes.BaseScene):
+    """Class that handles the contruction of a Three scene"""
     _defaults = {
         constants.METADATA: constants.DEFAULT_METADATA.copy(),
         constants.GEOMETRIES: [],
@@ -22,7 +23,7 @@ class Scene(base_classes.BaseScene):
     }
 
     def __init__(self, filepath, options=None):
-        logger.debug('Scene().__init__(%s, %s)', filepath, options)
+        logger.debug("Scene().__init__(%s, %s)", filepath, options)
         base_classes.BaseScene.__init__(self, filepath, options or {})
 
         source_file = api.scene_name()
@@ -31,67 +32,103 @@ class Scene(base_classes.BaseScene):
 
     @property
     def valid_types(self):
+        """
+
+        :return: list of valid node types
+
+        """
         valid_types = [api.constants.MESH]
 
         if self.options.get(constants.CAMERAS):
-            logger.info('Adding cameras to valid object types') 
+            logger.info("Adding cameras to valid object types")
             valid_types.append(api.constants.CAMERA)
 
         if self.options.get(constants.LIGHTS):
-            logger.info('Adding lights to valid object types') 
+            logger.info("Adding lights to valid object types")
             valid_types.append(api.constants.LAMP)
 
         return valid_types
 
-    def geometry(self, arg):
-        logger.debug('Scene().geometry(%s)', arg)
-        return self._find_node(arg, self[constants.GEOMETRIES])
+    def geometry(self, value):
+        """Find a geometry node that matches either a name
+        or uuid value.
+
+        :param value: name or uuid
+        :type value: str
+
+        """
+        logger.debug("Scene().geometry(%s)", value)
+        return _find_node(value, self[constants.GEOMETRIES])
+
+    def image(self, value):
+        """Find a image node that matches either a name
+        or uuid value.
 
-    def image(self, arg):
-        logger.debug('Scene().image%s)', arg)
-        return self._find_node(arg, self[constants.IMAGES])
+        :param value: name or uuid
+        :type value: str
 
-    def material(self, arg):
-        logger.debug('Scene().material(%s)', arg)
-        return self._find_node(arg, self[constants.MATERIALS])
+        """
+        logger.debug("Scene().image%s)", value)
+        return _find_node(value, self[constants.IMAGES])
+
+    def material(self, value):
+        """Find a material node that matches either a name
+        or uuid value.
+
+        :param value: name or uuid
+        :type value: str
+
+        """
+        logger.debug("Scene().material(%s)", value)
+        return _find_node(value, self[constants.MATERIALS])
 
     def parse(self):
-        logger.debug('Scene().parse()')
+        """Execute the parsing of the scene"""
+        logger.debug("Scene().parse()")
         if self.options.get(constants.MAPS):
-            self.__parse_textures()
+            self._parse_textures()
 
         if self.options.get(constants.MATERIALS):
-            self.__parse_materials()
+            self._parse_materials()
+
+        self._parse_geometries()
+        self._parse_objects()
 
-        self.__parse_geometries()
-        self.__parse_objects()
+    def texture(self, value):
+        """Find a texture node that matches either a name
+        or uuid value.
 
-    def texture(self, arg):
-        logger.debug('Scene().texture(%s)', arg)
-        return self._find_node(arg, self[constants.TEXTURES])
+        :param value: name or uuid
+        :type value: str
+
+        """
+        logger.debug("Scene().texture(%s)", value)
+        return _find_node(value, self[constants.TEXTURES])
 
     def write(self):
-        logger.debug('Scene().write()')
+        """Write the parsed scene to disk."""
+        logger.debug("Scene().write()")
         data = {}
-        
+
         embed_anim = self.options.get(constants.EMBED_ANIMATION, True)
         embed = self.options.get(constants.EMBED_GEOMETRY, True)
 
         compression = self.options.get(constants.COMPRESSION)
-        extension = constants.EXTENSIONS.get(compression, 
+        extension = constants.EXTENSIONS.get(
+            compression,
             constants.EXTENSIONS[constants.JSON])
 
         export_dir = os.path.dirname(self.filepath)
         for key, value in self.items():
-            
+
             if key == constants.GEOMETRIES:
                 geometries = []
-                for geometry in value:
+                for geom in value:
 
                     if not embed_anim:
-                        geometry.write_animation(export_dir)
+                        geom.write_animation(export_dir)
 
-                    geom_data = geometry.copy()
+                    geom_data = geom.copy()
                     if embed:
                         geometries.append(geom_data)
                         continue
@@ -103,10 +140,10 @@ class Scene(base_classes.BaseScene):
                         geom_data.pop(constants.ATTRIBUTES)
                         geom_data.pop(constants.METADATA)
 
-                    url = 'geometry.%s%s' % (geometry.node, extension)
+                    url = 'geometry.%s%s' % (geom.node, extension)
                     geometry_file = os.path.join(export_dir, url)
 
-                    geometry.write(filepath=geometry_file)
+                    geom.write(filepath=geometry_file)
                     geom_data[constants.URL] = os.path.basename(url)
 
                     geometries.append(geom_data)
@@ -123,20 +160,12 @@ class Scene(base_classes.BaseScene):
 
         if self.options.get(constants.COPY_TEXTURES):
             for geo in self[constants.GEOMETRIES]:
-                logger.info('Copying textures from %s', geo.node)
+                logger.info("Copying textures from %s", geo.node)
                 geo.copy_textures()
 
-    def _find_node(self, arg, manifest):
-        for index in manifest:
-            uuid = index.get(constants.UUID) == arg
-            name = index.node == arg
-            if uuid or name:
-                return index
-        else:
-            logger.debug('No matching node for %s', arg)
-
-    def __parse_geometries(self):
-        logger.debug('Scene().__parse_geometries()')
+    def _parse_geometries(self):
+        """Locate all geometry nodes and parse them"""
+        logger.debug("Scene()._parse_geometries()")
 
         # this is an important step. please refer to the doc string
         # on the function for more information
@@ -145,52 +174,75 @@ class Scene(base_classes.BaseScene):
 
         # now iterate over all the extracted mesh nodes and parse each one
         for mesh in api.object.extracted_meshes():
-            logger.info('Parsing geometry %s', mesh)
+            logger.info("Parsing geometry %s", mesh)
             geo = geometry.Geometry(mesh, self)
             geo.parse()
             geometries.append(geo)
 
-        logger.info('Added %d geometry nodes', len(geometries))
+        logger.info("Added %d geometry nodes", len(geometries))
         self[constants.GEOMETRIES] = geometries
 
-    def __parse_materials(self):
-        logger.debug('Scene().__parse_materials()')
+    def _parse_materials(self):
+        """Locate all non-orphaned materials and parse them"""
+        logger.debug("Scene()._parse_materials()")
         materials = []
 
         for material_name in api.material.used_materials():
-            logger.info('Parsing material %s', material_name)
-            materials.append(material.Material(material_name, parent=self)) 
+            logger.info("Parsing material %s", material_name)
+            materials.append(material.Material(material_name, parent=self))
 
-        logger.info('Added %d material nodes', len(materials))
+        logger.info("Added %d material nodes", len(materials))
         self[constants.MATERIALS] = materials
 
-    def __parse_objects(self): 
-        logger.debug('Scene().__parse_objects()')
+    def _parse_objects(self):
+        """Locate all valid objects in the scene and parse them"""
+        logger.debug("Scene()._parse_objects()")
         try:
             scene_name = self[constants.METADATA][constants.SOURCE_FILE]
         except KeyError:
             scene_name = constants.SCENE
-        self[constants.OBJECT] = object.Object(None, parent=self)
+        self[constants.OBJECT] = object_.Object(None, parent=self)
         self[constants.OBJECT][constants.TYPE] = constants.SCENE.title()
         self[constants.UUID] = utilities.id_from_name(scene_name)
 
-        objects = [] 
+        objects = []
         for node in api.object.assemblies(self.valid_types, self.options):
-            logger.info('Parsing object %s', node)
-            obj = object.Object(node, parent=self[constants.OBJECT])
+            logger.info("Parsing object %s", node)
+            obj = object_.Object(node, parent=self[constants.OBJECT])
             objects.append(obj)
 
-        logger.info('Added %d object nodes', len(objects))
+        logger.info("Added %d object nodes", len(objects))
         self[constants.OBJECT][constants.CHILDREN] = objects
 
-    def __parse_textures(self):
-        logger.debug('Scene().__parse_textures()')
+    def _parse_textures(self):
+        """Locate all non-orphaned textures and parse them"""
+        logger.debug("Scene()._parse_textures()")
         textures = []
 
         for texture_name in api.texture.textures():
-            logger.info('Parsing texture %s', texture_name)
+            logger.info("Parsing texture %s", texture_name)
             tex_inst = texture.Texture(texture_name, self)
             textures.append(tex_inst)
 
-        logger.info('Added %d texture nodes', len(textures))
+        logger.info("Added %d texture nodes", len(textures))
         self[constants.TEXTURES] = textures
+
+
+def _find_node(value, manifest):
+    """Find a node that matches either a name
+    or uuid value.
+
+    :param value: name or uuid
+    :param manifest: manifest of nodes to search
+    :type value: str
+    :type manifest: list
+
+    """
+    for index in manifest:
+        uuid = index.get(constants.UUID) == value
+        name = index.node == value
+        if uuid or name:
+            return index
+    else:
+        logger.debug("No matching node for %s", value)
+

+ 8 - 1
utils/exporters/blender/addons/io_three/exporter/texture.py

@@ -3,8 +3,9 @@ from . import base_classes, image, api
 
 
 class Texture(base_classes.BaseNode):
+    """Class that wraps a texture node"""
     def __init__(self, node, parent):
-        logger.debug('Texture().__init__(%s)', node)
+        logger.debug("Texture().__init__(%s)", node)
         base_classes.BaseNode.__init__(self, node, parent, constants.TEXTURE)
 
         img_inst = self.scene.image(api.texture.file_name(self.node))
@@ -29,4 +30,10 @@ class Texture(base_classes.BaseNode):
 
     @property
     def image(self):
+        """
+
+        :return: the image object of the current texture
+        :rtype: image.Image
+
+        """
         return self.scene.image(self[constants.IMAGE])

+ 51 - 5
utils/exporters/blender/addons/io_three/exporter/utilities.py

@@ -8,9 +8,15 @@ ROUND = constants.DEFAULT_PRECISION
 
 
 def bit_mask(flags):
+    """Generate a bit mask.
+
+    :type flags: dict
+    :return: int
+
+    """
     bit = 0
-    true = lambda x,y: (x | (1 << y))
-    false = lambda x,y: (x & (~(1 << y)))
+    true = lambda x, y: (x | (1 << y))
+    false = lambda x, y: (x & (~(1 << y)))
 
     for mask, position in constants.MASK.items():
         func = true if flags.get(mask) else false
@@ -20,19 +26,43 @@ def bit_mask(flags):
 
 
 def hash(value):
+    """Generate a hash from a given value
+
+    :param value:
+    :rtype: str
+
+    """
     hash_ = hashlib.md5()
     hash_.update(repr(value).encode('utf8'))
     return hash_.hexdigest()
 
 
 def id():
+    """Generate a random UUID
+
+    :rtype: str
+
+    """
     return str(uuid.uuid4()).upper()
 
+
 def id_from_name(name):
+    """Generate a UUID using a name as the namespace
+
+    :type name: str
+    :rtype: str
+
+    """
     return str(uuid.uuid3(uuid.NAMESPACE_DNS, name)).upper()
 
 
 def rgb2int(rgb):
+    """Convert a given rgb value to an integer
+
+    :type rgb: list|tuple
+    :rtype: int
+
+    """
     is_tuple = isinstance(rgb, tuple)
     rgb = list(rgb) if is_tuple else rgb
 
@@ -41,6 +71,15 @@ def rgb2int(rgb):
 
 
 def round_off(value, ndigits=ROUND):
+    """Round off values to specified limit
+
+    :param value: value(s) to round off
+    :param ndigits: limit (Default = ROUND)
+    :type value: float|list|tuple
+    :return: the same data type that was passed
+    :rtype: float|list|tuple
+
+    """
     is_tuple = isinstance(value, tuple)
     is_list = isinstance(value, list)
 
@@ -58,10 +97,17 @@ def round_off(value, ndigits=ROUND):
 
 
 def rounding(options):
-    round_off = options.get(constants.ENABLE_PRECISION)
-    if round_off:
+    """By evaluation the options determine if precision was
+    enabled and what the value is
+
+    :type options: dict
+    :rtype: bool, int
+
+    """
+    round_off_ = options.get(constants.ENABLE_PRECISION)
+    if round_off_:
         round_val = options[constants.PRECISION]
     else:
         round_val = None
 
-    return (round_off, round_val)
+    return (round_off_, round_val)

+ 7 - 0
utils/exporters/blender/addons/io_three/logger.py

@@ -15,7 +15,14 @@ LEVELS = {
     constants.CRITICAL: logging.CRITICAL
 }
 
+
 def init(filename, level=constants.DEBUG):
+    """Initialize the logger.
+
+    :param filename: base name of the log file
+    :param level: logging level (Default = DEBUG)
+
+    """
     global LOG_FILE
     LOG_FILE = os.path.join(tempfile.gettempdir(), filename)
     with open(LOG_FILE, 'w'):