Cleanup: pep8

This commit is contained in:
Campbell Barton
2018-07-03 06:47:49 +02:00
parent b66aa0b0a6
commit 8c15d612a5
31 changed files with 593 additions and 485 deletions

View File

@@ -7,7 +7,7 @@
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
@@ -22,21 +22,21 @@
# #
# Name: # Name:
# dna.py # dna.py
# #
# Description: # Description:
# Creates a browsable DNA output to HTML. # Creates a browsable DNA output to HTML.
# #
# Author: # Author:
# Jeroen Bakker # Jeroen Bakker
# #
# Version: # Version:
# v0.1 (12-05-2009) - migration of original source code to python. # v0.1 (12-05-2009) - migration of original source code to python.
# Added code to support blender 2.5 branch # Added code to support blender 2.5 branch
# v0.2 (25-05-2009) - integrated with BlendFileReader.py # v0.2 (25-05-2009) - integrated with BlendFileReader.py
# #
# Input: # Input:
# blender build executable # blender build executable
# #
# Output: # Output:
# dna.html # dna.html
# dna.css (will only be created when not existing) # dna.css (will only be created when not existing)
@@ -76,12 +76,12 @@ class DNACatalogHTML:
DNACatalog is a catalog of all information in the DNA1 file-block DNACatalog is a catalog of all information in the DNA1 file-block
''' '''
def __init__(self, catalog, bpy_module = None): def __init__(self, catalog, bpy_module=None):
self.Catalog = catalog self.Catalog = catalog
self.bpy = bpy_module self.bpy = bpy_module
def WriteToHTML(self, handle): def WriteToHTML(self, handle):
dna_html_template = """ dna_html_template = """
<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd> <!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd>
<html> <html>
@@ -105,10 +105,10 @@ class DNACatalogHTML:
${structs_content} ${structs_content}
</body> </body>
</html>""" </html>"""
header = self.Catalog.Header header = self.Catalog.Header
bpy = self.bpy bpy = self.bpy
# ${version} and ${revision} # ${version} and ${revision}
if bpy: if bpy:
version = '.'.join(map(str, bpy.app.version)) version = '.'.join(map(str, bpy.app.version))
@@ -116,7 +116,7 @@ class DNACatalogHTML:
else: else:
version = str(header.Version) version = str(header.Version)
revision = 'Unknown' revision = 'Unknown'
# ${bitness} # ${bitness}
if header.PointerSize == 8: if header.PointerSize == 8:
bitness = '64 bit' bitness = '64 bit'
@@ -125,10 +125,10 @@ class DNACatalogHTML:
# ${endianness} # ${endianness}
if header.LittleEndianness: if header.LittleEndianness:
endianess= 'Little endianness' endianess = 'Little endianness'
else: else:
endianess= 'Big endianness' endianess = 'Big endianness'
# ${structs_list} # ${structs_list}
log.debug("Creating structs index") log.debug("Creating structs index")
structs_list = '' structs_list = ''
@@ -136,7 +136,7 @@ class DNACatalogHTML:
structureIndex = 0 structureIndex = 0
for structure in self.Catalog.Structs: for structure in self.Catalog.Structs:
structs_list += list_item.format(structureIndex, structure.Type.Name) structs_list += list_item.format(structureIndex, structure.Type.Name)
structureIndex+=1 structureIndex += 1
# ${structs_content} # ${structs_content}
log.debug("Creating structs content") log.debug("Creating structs content")
@@ -144,20 +144,20 @@ class DNACatalogHTML:
for structure in self.Catalog.Structs: for structure in self.Catalog.Structs:
log.debug(structure.Type.Name) log.debug(structure.Type.Name)
structs_content += self.Structure(structure) structs_content += self.Structure(structure)
d = dict( d = dict(
version = version, version=version,
revision = revision, revision=revision,
bitness = bitness, bitness=bitness,
endianness = endianess, endianness=endianess,
structs_list = structs_list, structs_list=structs_list,
structs_content = structs_content structs_content=structs_content
) )
dna_html = Template(dna_html_template).substitute(d) dna_html = Template(dna_html_template).substitute(d)
dna_html = self.format(dna_html) dna_html = self.format(dna_html)
handle.write(dna_html) handle.write(dna_html)
def Structure(self, structure): def Structure(self, structure):
struct_table_template = """ struct_table_template = """
<table><a name="${struct_name}"></a> <table><a name="${struct_name}"></a>
@@ -178,23 +178,23 @@ class DNACatalogHTML:
</table> </table>
<label>Total size: ${size} bytes</label><br/> <label>Total size: ${size} bytes</label><br/>
<label>(<a href="#top">top</a>)</label><br/>""" <label>(<a href="#top">top</a>)</label><br/>"""
d = dict( d = dict(
struct_name = structure.Type.Name, struct_name=structure.Type.Name,
fields = self.StructureFields(structure, None, 0), fields=self.StructureFields(structure, None, 0),
size = str(structure.Type.Size) size=str(structure.Type.Size)
) )
struct_table = Template(struct_table_template).substitute(d) struct_table = Template(struct_table_template).substitute(d)
return struct_table return struct_table
def StructureFields(self, structure, parentReference, offset): def StructureFields(self, structure, parentReference, offset):
fields = '' fields = ''
for field in structure.Fields: for field in structure.Fields:
fields += self.StructureField(field, structure, parentReference, offset) fields += self.StructureField(field, structure, parentReference, offset)
offset += field.Size(self.Catalog.Header) offset += field.Size(self.Catalog.Header)
return fields return fields
def StructureField(self, field, structure, parentReference, offset): def StructureField(self, field, structure, parentReference, offset):
structure_field_template = """ structure_field_template = """
<tr> <tr>
@@ -205,7 +205,7 @@ class DNACatalogHTML:
<td>${offset}</td> <td>${offset}</td>
<td>${size}</td> <td>${size}</td>
</tr>""" </tr>"""
if field.Type.Structure is None or field.Name.IsPointer(): if field.Type.Structure is None or field.Name.IsPointer():
# ${reference} # ${reference}
@@ -216,37 +216,37 @@ class DNACatalogHTML:
struct = '<a href="#{0}">{0}</a>'.format(structure.Type.Name) struct = '<a href="#{0}">{0}</a>'.format(structure.Type.Name)
else: else:
struct = structure.Type.Name struct = structure.Type.Name
# ${type} # ${type}
type = field.Type.Name type = field.Type.Name
# ${name} # ${name}
name = field.Name.Name name = field.Name.Name
# ${offset} # ${offset}
# offset already set # offset already set
# ${size} # ${size}
size = field.Size(self.Catalog.Header) size = field.Size(self.Catalog.Header)
d = dict( d = dict(
reference = reference, reference=reference,
struct = struct, struct=struct,
type = type, type=type,
name = name, name=name,
offset = offset, offset=offset,
size = size size=size
) )
structure_field = Template(structure_field_template).substitute(d) structure_field = Template(structure_field_template).substitute(d)
elif field.Type.Structure is not None: elif field.Type.Structure is not None:
reference = field.Name.AsReference(parentReference) reference = field.Name.AsReference(parentReference)
structure_field = self.StructureFields(field.Type.Structure, reference, offset) structure_field = self.StructureFields(field.Type.Structure, reference, offset)
return structure_field return structure_field
def indent(self, input, dent, startswith = ''): def indent(self, input, dent, startswith=''):
output = '' output = ''
if dent < 0: if dent < 0:
for line in input.split('\n'): for line in input.split('\n'):
@@ -257,19 +257,19 @@ class DNACatalogHTML:
output += line.lstrip() + '\n' # remove indentation completely output += line.lstrip() + '\n' # remove indentation completely
elif dent > 0: elif dent > 0:
for line in input.split('\n'): for line in input.split('\n'):
output += ' '* dent + line + '\n' output += ' ' * dent + line + '\n'
return output return output
def format(self, input): def format(self, input):
diff = { diff = {
'\n<!DOCTYPE':'<!DOCTYPE', '\n<!DOCTYPE': '<!DOCTYPE',
'\n</ul>' :'</ul>', '\n</ul>': '</ul>',
'<a name' :'\n<a name', '<a name': '\n<a name',
'<tr>\n' :'<tr>', '<tr>\n': '<tr>',
'<tr>' :' <tr>', '<tr>': ' <tr>',
'</th>\n' :'</th>', '</th>\n': '</th>',
'</td>\n' :'</td>', '</td>\n': '</td>',
'<tbody>\n' :'<tbody>' '<tbody>\n': '<tbody>'
} }
output = self.indent(input, 0) output = self.indent(input, 0)
for key, value in diff.items(): for key, value in diff.items():
@@ -283,17 +283,17 @@ class DNACatalogHTML:
''' '''
css = """ css = """
@CHARSET "ISO-8859-1"; @CHARSET "ISO-8859-1";
body { body {
font-family: verdana; font-family: verdana;
font-size: small; font-size: small;
} }
div.title { div.title {
font-size: large; font-size: large;
text-align: center; text-align: center;
} }
h1 { h1 {
page-break-before: always; page-break-before: always;
} }
@@ -304,7 +304,7 @@ class DNACatalogHTML:
margin-right: 3%; margin-right: 3%;
padding-left: 40px; padding-left: 40px;
} }
h1:hover{ h1:hover{
background-color: #EBEBEB; background-color: #EBEBEB;
} }
@@ -312,7 +312,7 @@ class DNACatalogHTML:
h3 { h3 {
padding-left: 40px; padding-left: 40px;
} }
table { table {
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
@@ -321,21 +321,21 @@ class DNACatalogHTML:
width: 94%; width: 94%;
margin: 20px 3% 10px; margin: 20px 3% 10px;
} }
caption { caption {
margin-bottom: 5px; margin-bottom: 5px;
} }
th { th {
background-color: #000000; background-color: #000000;
color:#ffffff; color:#ffffff;
padding-left:5px; padding-left:5px;
padding-right:5px; padding-right:5px;
} }
tr { tr {
} }
td { td {
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
@@ -343,12 +343,12 @@ class DNACatalogHTML:
padding-left:5px; padding-left:5px;
padding-right:5px; padding-right:5px;
} }
label { label {
float:right; float:right;
margin-right: 3%; margin-right: 3%;
} }
ul.multicolumn { ul.multicolumn {
list-style:none; list-style:none;
float:left; float:left;
@@ -361,18 +361,18 @@ class DNACatalogHTML:
width:200px; width:200px;
margin-right:0px; margin-right:0px;
} }
a { a {
color:#a000a0; color:#a000a0;
text-decoration:none; text-decoration:none;
} }
a:hover { a:hover {
color:#a000a0; color:#a000a0;
text-decoration:underline; text-decoration:underline;
} }
""" """
css = self.indent(css, 0) css = self.indent(css, 0)
handle.write(css) handle.write(css)
@@ -389,13 +389,13 @@ def usage():
print("\tdefault: % blender2.5 --background -noaudio --python BlendFileDnaExporter_25.py") print("\tdefault: % blender2.5 --background -noaudio --python BlendFileDnaExporter_25.py")
print("\twith options: % blender2.5 --background -noaudio --python BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug\n") print("\twith options: % blender2.5 --background -noaudio --python BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug\n")
###################################################### ######################################################
# Main # Main
###################################################### ######################################################
def main(): def main():
import os, os.path import os, os.path
try: try:
@@ -408,37 +408,37 @@ def main():
else: else:
filename = 'dna' filename = 'dna'
dir = os.path.dirname(__file__) dir = os.path.dirname(__file__)
Path_Blend = os.path.join(dir, filename + '.blend') # temporary blend file Path_Blend = os.path.join(dir, filename + '.blend') # temporary blend file
Path_HTML = os.path.join(dir, filename + '.html') # output html file Path_HTML = os.path.join(dir, filename + '.html') # output html file
Path_CSS = os.path.join(dir, 'dna.css') # output css file Path_CSS = os.path.join(dir, 'dna.css') # output css file
# create a blend file for dna parsing # create a blend file for dna parsing
if not os.path.exists(Path_Blend): if not os.path.exists(Path_Blend):
log.info("1: write temp blend file with SDNA info") log.info("1: write temp blend file with SDNA info")
log.info(" saving to: " + Path_Blend) log.info(" saving to: " + Path_Blend)
try: try:
bpy.ops.wm.save_as_mainfile(filepath = Path_Blend, copy = True, compress = False) bpy.ops.wm.save_as_mainfile(filepath=Path_Blend, copy=True, compress=False)
except: except:
log.error("Filename {0} does not exist and can't be created... quitting".format(Path_Blend)) log.error("Filename {0} does not exist and can't be created... quitting".format(Path_Blend))
return return
else: else:
log.info("1: found blend file with SDNA info") log.info("1: found blend file with SDNA info")
log.info(" " + Path_Blend) log.info(" " + Path_Blend)
# read blend header from blend file # read blend header from blend file
log.info("2: read file:") log.info("2: read file:")
if not dir in sys.path: if not dir in sys.path:
sys.path.append(dir) sys.path.append(dir)
import BlendFileReader import BlendFileReader
handle = BlendFileReader.openBlendFile(Path_Blend) handle = BlendFileReader.openBlendFile(Path_Blend)
blendfile = BlendFileReader.BlendFile(handle) blendfile = BlendFileReader.BlendFile(handle)
catalog = DNACatalogHTML(blendfile.Catalog, bpy) catalog = DNACatalogHTML(blendfile.Catalog, bpy)
# close temp file # close temp file
handle.close() handle.close()
# deleting or not? # deleting or not?
if '--dna-keep-blend' in sys.argv: if '--dna-keep-blend' in sys.argv:
# keep the blend, useful for studying hexdumps # keep the blend, useful for studying hexdumps
@@ -449,7 +449,7 @@ def main():
log.info("5: close and delete temp blend:") log.info("5: close and delete temp blend:")
log.info(" {0}".format(Path_Blend)) log.info(" {0}".format(Path_Blend))
os.remove(Path_Blend) os.remove(Path_Blend)
# export dna to xhtml # export dna to xhtml
log.info("6: export sdna to xhtml file: %r" % Path_HTML) log.info("6: export sdna to xhtml file: %r" % Path_HTML)
handleHTML = open(Path_HTML, "w") handleHTML = open(Path_HTML, "w")
@@ -466,12 +466,12 @@ def main():
if not bpy.app.background: if not bpy.app.background:
log.info("7: quit blender") log.info("7: quit blender")
bpy.ops.wm.exit_blender() bpy.ops.wm.exit_blender()
except ImportError: except ImportError:
log.warning(" skipping, not running in Blender") log.warning(" skipping, not running in Blender")
usage() usage()
sys.exit(2) sys.exit(2)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@@ -7,7 +7,7 @@
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
@@ -34,6 +34,7 @@ log = logging.getLogger("BlendFileReader")
# module global routines # module global routines
###################################################### ######################################################
def ReadString(handle, length): def ReadString(handle, length):
''' '''
ReadString reads a String of given length or a zero terminating String ReadString reads a String of given length or a zero terminating String
@@ -45,7 +46,7 @@ def ReadString(handle, length):
# length == 0 means we want a zero terminating string # length == 0 means we want a zero terminating string
result = "" result = ""
s = ReadString(handle, 1) s = ReadString(handle, 1)
while s!="\0": while s != "\0":
result += s result += s
s = ReadString(handle, 1) s = ReadString(handle, 1)
return result return result
@@ -57,7 +58,7 @@ def Read(type, handle, fileheader):
''' '''
def unpacked_bytes(type_char, size): def unpacked_bytes(type_char, size):
return struct.unpack(fileheader.StructPre + type_char, handle.read(size))[0] return struct.unpack(fileheader.StructPre + type_char, handle.read(size))[0]
if type == 'ushort': if type == 'ushort':
return unpacked_bytes("H", 2) # unsigned short return unpacked_bytes("H", 2) # unsigned short
elif type == 'short': elif type == 'short':
@@ -94,10 +95,10 @@ def openBlendFile(filename):
log.debug("decompressing started") log.debug("decompressing started")
fs = gzip.open(filename, "rb") fs = gzip.open(filename, "rb")
handle = tempfile.TemporaryFile() handle = tempfile.TemporaryFile()
data = fs.read(1024*1024) data = fs.read(1024 * 1024)
while data: while data:
handle.write(data) handle.write(data)
data = fs.read(1024*1024) data = fs.read(1024 * 1024)
log.debug("decompressing finished") log.debug("decompressing finished")
fs.close() fs.close()
log.debug("resetting decompressed file") log.debug("resetting decompressed file")
@@ -112,7 +113,7 @@ def Align(handle):
offset = handle.tell() offset = handle.tell()
trim = offset % 4 trim = offset % 4
if trim != 0: if trim != 0:
handle.seek(4-trim, os.SEEK_CUR) handle.seek(4 - trim, os.SEEK_CUR)
###################################################### ######################################################
@@ -121,14 +122,14 @@ def Align(handle):
class BlendFile: class BlendFile:
''' '''
Reads a blendfile and store the header, all the fileblocks, and catalogue Reads a blendfile and store the header, all the fileblocks, and catalogue
structs foound in the DNA fileblock structs foound in the DNA fileblock
- BlendFile.Header (BlendFileHeader instance) - BlendFile.Header (BlendFileHeader instance)
- BlendFile.Blocks (list of BlendFileBlock instances) - BlendFile.Blocks (list of BlendFileBlock instances)
- BlendFile.Catalog (DNACatalog instance) - BlendFile.Catalog (DNACatalog instance)
''' '''
def __init__(self, handle): def __init__(self, handle):
log.debug("initializing reading blend-file") log.debug("initializing reading blend-file")
self.Header = BlendFileHeader(handle) self.Header = BlendFileHeader(handle)
@@ -141,13 +142,13 @@ class BlendFile:
found_dna_block = True found_dna_block = True
else: else:
fileblock.Header.skip(handle) fileblock.Header.skip(handle)
self.Blocks.append(fileblock) self.Blocks.append(fileblock)
fileblock = BlendFileBlock(handle, self) fileblock = BlendFileBlock(handle, self)
# appending last fileblock, "ENDB" # appending last fileblock, "ENDB"
self.Blocks.append(fileblock) self.Blocks.append(fileblock)
# seems unused? # seems unused?
""" """
def FindBlendFileBlocksWithCode(self, code): def FindBlendFileBlocksWithCode(self, code):
@@ -164,27 +165,27 @@ class BlendFileHeader:
BlendFileHeader allocates the first 12 bytes of a blend file. BlendFileHeader allocates the first 12 bytes of a blend file.
It contains information about the hardware architecture. It contains information about the hardware architecture.
Header example: BLENDER_v254 Header example: BLENDER_v254
BlendFileHeader.Magic (str) BlendFileHeader.Magic (str)
BlendFileHeader.PointerSize (int) BlendFileHeader.PointerSize (int)
BlendFileHeader.LittleEndianness (bool) BlendFileHeader.LittleEndianness (bool)
BlendFileHeader.StructPre (str) see http://docs.python.org/py3k/library/struct.html#byte-order-size-and-alignment BlendFileHeader.StructPre (str) see http://docs.python.org/py3k/library/struct.html#byte-order-size-and-alignment
BlendFileHeader.Version (int) BlendFileHeader.Version (int)
''' '''
def __init__(self, handle): def __init__(self, handle):
log.debug("reading blend-file-header") log.debug("reading blend-file-header")
self.Magic = ReadString(handle, 7) self.Magic = ReadString(handle, 7)
log.debug(self.Magic) log.debug(self.Magic)
pointersize = ReadString(handle, 1) pointersize = ReadString(handle, 1)
log.debug(pointersize) log.debug(pointersize)
if pointersize == "-": if pointersize == "-":
self.PointerSize = 8 self.PointerSize = 8
if pointersize == "_": if pointersize == "_":
self.PointerSize = 4 self.PointerSize = 4
endianness = ReadString(handle, 1) endianness = ReadString(handle, 1)
log.debug(endianness) log.debug(endianness)
if endianness == "v": if endianness == "v":
@@ -193,11 +194,11 @@ class BlendFileHeader:
if endianness == "V": if endianness == "V":
self.LittleEndianness = False self.LittleEndianness = False
self.StructPre = ">" self.StructPre = ">"
version = ReadString(handle, 3) version = ReadString(handle, 3)
log.debug(version) log.debug(version)
self.Version = int(version) self.Version = int(version)
log.debug("{0} {1} {2} {3}".format(self.Magic, self.PointerSize, self.LittleEndianness, version)) log.debug("{0} {1} {2} {3}".format(self.Magic, self.PointerSize, self.LittleEndianness, version))
@@ -206,11 +207,11 @@ class BlendFileBlock:
BlendFileBlock.File (BlendFile) BlendFileBlock.File (BlendFile)
BlendFileBlock.Header (FileBlockHeader) BlendFileBlock.Header (FileBlockHeader)
''' '''
def __init__(self, handle, blendfile): def __init__(self, handle, blendfile):
self.File = blendfile self.File = blendfile
self.Header = FileBlockHeader(handle, blendfile.Header) self.Header = FileBlockHeader(handle, blendfile.Header)
def Get(self, handle, path): def Get(self, handle, path):
log.debug("find dna structure") log.debug("find dna structure")
dnaIndex = self.Header.SDNAIndex dnaIndex = self.Header.SDNAIndex
@@ -232,7 +233,7 @@ class FileBlockHeader:
Count (int) Count (int)
FileOffset (= file pointer of datablock) FileOffset (= file pointer of datablock)
''' '''
def __init__(self, handle, fileheader): def __init__(self, handle, fileheader):
self.Code = ReadString(handle, 4).strip() self.Code = ReadString(handle, 4).strip()
if self.Code != "ENDB": if self.Code != "ENDB":
@@ -257,28 +258,28 @@ class FileBlockHeader:
class DNACatalog: class DNACatalog:
''' '''
DNACatalog is a catalog of all information in the DNA1 file-block DNACatalog is a catalog of all information in the DNA1 file-block
Header = None Header = None
Names = None Names = None
Types = None Types = None
Structs = None Structs = None
''' '''
def __init__(self, fileheader, handle): def __init__(self, fileheader, handle):
log.debug("building DNA catalog") log.debug("building DNA catalog")
self.Names=[] self.Names = []
self.Types=[] self.Types = []
self.Structs=[] self.Structs = []
self.Header = fileheader self.Header = fileheader
SDNA = ReadString(handle, 4) SDNA = ReadString(handle, 4)
# names # names
NAME = ReadString(handle, 4) NAME = ReadString(handle, 4)
numberOfNames = Read('uint', handle, fileheader) numberOfNames = Read('uint', handle, fileheader)
log.debug("building #{0} names".format(numberOfNames)) log.debug("building #{0} names".format(numberOfNames))
for i in range(numberOfNames): for i in range(numberOfNames):
name = ReadString(handle,0) name = ReadString(handle, 0)
self.Names.append(DNAName(name)) self.Names.append(DNAName(name))
Align(handle) Align(handle)
@@ -287,7 +288,7 @@ class DNACatalog:
numberOfTypes = Read('uint', handle, fileheader) numberOfTypes = Read('uint', handle, fileheader)
log.debug("building #{0} types".format(numberOfTypes)) log.debug("building #{0} types".format(numberOfTypes))
for i in range(numberOfTypes): for i in range(numberOfTypes):
type = ReadString(handle,0) type = ReadString(handle, 0)
self.Types.append(DNAType(type)) self.Types.append(DNAType(type))
Align(handle) Align(handle)
@@ -321,24 +322,24 @@ class DNACatalog:
class DNAName: class DNAName:
''' '''
DNAName is a C-type name stored in the DNA. DNAName is a C-type name stored in the DNA.
Name = str Name = str
''' '''
def __init__(self, name): def __init__(self, name):
self.Name = name self.Name = name
def AsReference(self, parent): def AsReference(self, parent):
if parent is None: if parent is None:
result = "" result = ""
else: else:
result = parent+"." result = parent + "."
result = result + self.ShortName() result = result + self.ShortName()
return result return result
def ShortName(self): def ShortName(self):
result = self.Name; result = self.Name
result = result.replace("*", "") result = result.replace("*", "")
result = result.replace("(", "") result = result.replace("(", "")
result = result.replace(")", "") result = result.replace(")", "")
@@ -346,12 +347,12 @@ class DNAName:
if Index != -1: if Index != -1:
result = result[0:Index] result = result[0:Index]
return result return result
def IsPointer(self): def IsPointer(self):
return self.Name.find("*")>-1 return self.Name.find("*") > -1
def IsMethodPointer(self): def IsMethodPointer(self):
return self.Name.find("(*")>-1 return self.Name.find("(*") > -1
def ArraySize(self): def ArraySize(self):
result = 1 result = 1
@@ -360,10 +361,10 @@ class DNAName:
while Index != -1: while Index != -1:
Index2 = Temp.find("]") Index2 = Temp.find("]")
result*=int(Temp[Index+1:Index2]) result *= int(Temp[Index + 1:Index2])
Temp = Temp[Index2+1:] Temp = Temp[Index2 + 1:]
Index = Temp.find("[") Index = Temp.find("[")
return result return result
@@ -375,46 +376,46 @@ class DNAType:
Size = int Size = int
Structure = DNAStructure Structure = DNAStructure
''' '''
def __init__(self, aName): def __init__(self, aName):
self.Name = aName self.Name = aName
self.Structure=None self.Structure = None
class DNAStructure: class DNAStructure:
''' '''
DNAType is a C-type structure stored in the DNA DNAType is a C-type structure stored in the DNA
Type = DNAType Type = DNAType
Fields = [DNAField] Fields = [DNAField]
''' '''
def __init__(self, aType): def __init__(self, aType):
self.Type = aType self.Type = aType
self.Type.Structure = self self.Type.Structure = self
self.Fields=[] self.Fields = []
def GetField(self, header, handle, path): def GetField(self, header, handle, path):
splitted = path.partition(".") splitted = path.partition(".")
name = splitted[0] name = splitted[0]
rest = splitted[2] rest = splitted[2]
offset = 0; offset = 0
for field in self.Fields: for field in self.Fields:
if field.Name.ShortName() == name: if field.Name.ShortName() == name:
log.debug("found "+name+"@"+str(offset)) log.debug("found " + name + "@" + str(offset))
handle.seek(offset, os.SEEK_CUR) handle.seek(offset, os.SEEK_CUR)
return field.DecodeField(header, handle, rest) return field.DecodeField(header, handle, rest)
else: else:
offset += field.Size(header) offset += field.Size(header)
log.debug("error did not find "+path) log.debug("error did not find " + path)
return None return None
class DNAField: class DNAField:
''' '''
DNAField is a coupled DNAType and DNAName. DNAField is a coupled DNAType and DNAName.
Type = DNAType Type = DNAType
Name = DNAName Name = DNAName
''' '''
@@ -422,25 +423,24 @@ class DNAField:
def __init__(self, aType, aName): def __init__(self, aType, aName):
self.Type = aType self.Type = aType
self.Name = aName self.Name = aName
def Size(self, header): def Size(self, header):
if self.Name.IsPointer() or self.Name.IsMethodPointer(): if self.Name.IsPointer() or self.Name.IsMethodPointer():
return header.PointerSize*self.Name.ArraySize() return header.PointerSize * self.Name.ArraySize()
else: else:
return self.Type.Size*self.Name.ArraySize() return self.Type.Size * self.Name.ArraySize()
def DecodeField(self, header, handle, path): def DecodeField(self, header, handle, path):
if path == "": if path == "":
if self.Name.IsPointer(): if self.Name.IsPointer():
return Read('pointer', handle, header) return Read('pointer', handle, header)
if self.Type.Name=="int": if self.Type.Name == "int":
return Read('int', handle, header) return Read('int', handle, header)
if self.Type.Name=="short": if self.Type.Name == "short":
return Read('short', handle, header) return Read('short', handle, header)
if self.Type.Name=="float": if self.Type.Name == "float":
return Read('float', handle, header) return Read('float', handle, header)
if self.Type.Name=="char": if self.Type.Name == "char":
return ReadString(handle, self.Name.ArraySize()) return ReadString(handle, self.Name.ArraySize())
else: else:
return self.Type.Structure.GetField(header, handle, path) return self.Type.Structure.GetField(header, handle, path)

View File

@@ -42,6 +42,7 @@ def man_format(data):
data = data.replace("\t", " ") data = data.replace("\t", " ")
return data return data
if len(sys.argv) != 3: if len(sys.argv) != 3:
import getopt import getopt
raise getopt.GetoptError("Usage: %s <path-to-blender> <output-filename>" % sys.argv[0]) raise getopt.GetoptError("Usage: %s <path-to-blender> <output-filename>" % sys.argv[0])

View File

@@ -73,6 +73,8 @@ def rna_info_BuildRNAInfo_cache():
if rna_info_BuildRNAInfo_cache.ret is None: if rna_info_BuildRNAInfo_cache.ret is None:
rna_info_BuildRNAInfo_cache.ret = rna_info.BuildRNAInfo() rna_info_BuildRNAInfo_cache.ret = rna_info.BuildRNAInfo()
return rna_info_BuildRNAInfo_cache.ret return rna_info_BuildRNAInfo_cache.ret
rna_info_BuildRNAInfo_cache.ret = None rna_info_BuildRNAInfo_cache.ret = None
# --- end rna_info cache # --- end rna_info cache
@@ -431,7 +433,7 @@ else:
BLENDER_VERSION_DOTS = ".".join(blender_version_strings) BLENDER_VERSION_DOTS = ".".join(blender_version_strings)
if BLENDER_REVISION != "Unknown": if BLENDER_REVISION != "Unknown":
# '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release) # '2.62a SHA1' (release) or '2.62.1 SHA1' (non-release)
BLENDER_VERSION_DOTS += " " + BLENDER_REVISION BLENDER_VERSION_DOTS += " " + BLENDER_REVISION
if is_release: if is_release:
# '2_62a_release' # '2_62a_release'
@@ -513,6 +515,8 @@ def escape_rst(text):
""" Escape plain text which may contain characters used by RST. """ Escape plain text which may contain characters used by RST.
""" """
return text.translate(escape_rst.trans) return text.translate(escape_rst.trans)
escape_rst.trans = str.maketrans({ escape_rst.trans = str.maketrans({
"`": "\\`", "`": "\\`",
"|": "\\|", "|": "\\|",
@@ -1015,6 +1019,7 @@ def pymodule2sphinx(basepath, module_name, module, title):
file.close() file.close()
# Changes in Blender will force errors here # Changes in Blender will force errors here
context_type_map = { context_type_map = {
"active_base": ("ObjectBase", False), "active_base": ("ObjectBase", False),

View File

@@ -68,7 +68,7 @@ def image_from_file(filepath):
if bpy is not None: if bpy is not None:
pixels, pixel_w, pixel_h = image_from_file__bpy(filepath) pixels, pixel_w, pixel_h = image_from_file__bpy(filepath)
#else: # else:
# pixels, pixel_w, pixel_h = image_from_file__py(filepath) # pixels, pixel_w, pixel_h = image_from_file__py(filepath)
return pixels, pixel_w, pixel_h return pixels, pixel_w, pixel_h
@@ -95,12 +95,14 @@ def write_subimage(sub_x, sub_y, sub_w, sub_h,
with open(filepath, 'wb') as f: with open(filepath, 'wb') as f:
f.write(struct.pack('<6I', f.write(
struct.pack(
'<6I',
sub_w, sub_h, sub_w, sub_h,
sub_x, sub_y, sub_x, sub_y,
# redundant but including to maintain consistency # redundant but including to maintain consistency
pixel_w, pixel_h, pixel_w, pixel_h,
)) ))
for y in range(sub_h): for y in range(sub_h):
for x in range(sub_w): for x in range(sub_w):
@@ -113,8 +115,9 @@ def write_subimage(sub_x, sub_y, sub_w, sub_h,
_dice_icon_name_cache = {} _dice_icon_name_cache = {}
def dice_icon_name(x, y, parts_x, parts_y, def dice_icon_name(
name_style=None, prefix=""): x, y, parts_x, parts_y,
name_style=None, prefix=""):
""" """
How to name icons, this is mainly for what name we get in git, How to name icons, this is mainly for what name we get in git,
the actual names don't really matter, its just nice to have the the actual names don't really matter, its just nice to have the
@@ -143,7 +146,7 @@ def dice_icon_name(x, y, parts_x, parts_y,
icon_name = _dice_icon_name_cache[index] icon_name = _dice_icon_name_cache[index]
# for debugging its handy to sort by number # for debugging its handy to sort by number
#~ id_str = "%03d_%s%s.dat" % (index, prefix, icon_name) # ~ id_str = "%03d_%s%s.dat" % (index, prefix, icon_name)
id_str = "%s%s.dat" % (prefix, icon_name) id_str = "%s%s.dat" % (prefix, icon_name)
@@ -158,16 +161,18 @@ def dice_icon_name(x, y, parts_x, parts_y,
return id_str return id_str
def dice(filepath, output, output_prefix, name_style, def dice(
parts_x, parts_y, filepath, output, output_prefix, name_style,
minx, miny, maxx, maxy, parts_x, parts_y,
minx_icon, miny_icon, maxx_icon, maxy_icon, minx, miny, maxx, maxy,
spacex_icon, spacey_icon, minx_icon, miny_icon, maxx_icon, maxy_icon,
): spacex_icon, spacey_icon,
):
is_simple = (max(minx, miny, maxx, maxy, is_simple = (max(
minx_icon, miny_icon, maxx_icon, maxy_icon, minx, miny, maxx, maxy,
spacex_icon, spacey_icon) == 0) minx_icon, miny_icon, maxx_icon, maxy_icon,
spacex_icon, spacey_icon) == 0)
pixels, pixel_w, pixel_h = image_from_file(filepath) pixels, pixel_w, pixel_h = image_from_file(filepath)
@@ -199,9 +204,11 @@ def dice(filepath, output, output_prefix, name_style,
for x in range(parts_x): for x in range(parts_x):
for y in range(parts_y): for y in range(parts_y):
id_str = dice_icon_name(x, y, id_str = dice_icon_name(
parts_x, parts_y, x, y,
name_style=name_style, prefix=output_prefix) parts_x, parts_y,
name_style=name_style, prefix=output_prefix
)
filepath = os.path.join(output, id_str) filepath = os.path.join(output, id_str)
if VERBOSE: if VERBOSE:
print(" writing:", filepath) print(" writing:", filepath)
@@ -235,25 +242,35 @@ def main():
parser = argparse.ArgumentParser(description=__doc__, epilog=epilog) parser = argparse.ArgumentParser(description=__doc__, epilog=epilog)
# File path options # File path options
parser.add_argument("--image", dest="image", metavar='FILE', parser.add_argument(
help="Image file") "--image", dest="image", metavar='FILE',
help="Image file",
parser.add_argument("--output", dest="output", metavar='DIR', )
help="Output directory") parser.add_argument(
"--output", dest="output", metavar='DIR',
parser.add_argument("--output_prefix", dest="output_prefix", metavar='STRING', help="Output directory",
help="Output prefix") )
parser.add_argument(
"--output_prefix", dest="output_prefix", metavar='STRING',
help="Output prefix",
)
# Icon naming option # Icon naming option
parser.add_argument("--name_style", dest="name_style", metavar='ENUM', type=str, parser.add_argument(
choices=('', 'UI_ICONS'), "--name_style", dest="name_style", metavar='ENUM', type=str,
help="The metod used for naming output data") choices=('', 'UI_ICONS'),
help="The metod used for naming output data",
)
# Options for dicing up the image # Options for dicing up the image
parser.add_argument("--parts_x", dest="parts_x", metavar='INT', type=int, parser.add_argument(
help="Grid X parts") "--parts_x", dest="parts_x", metavar='INT', type=int,
parser.add_argument("--parts_y", dest="parts_y", metavar='INT', type=int, help="Grid X parts",
help="Grid Y parts") )
parser.add_argument(
"--parts_y", dest="parts_y", metavar='INT', type=int,
help="Grid Y parts",
)
_help = "Inset from the outer edge (in pixels)" _help = "Inset from the outer edge (in pixels)"
parser.add_argument("--minx", dest="minx", metavar='INT', type=int, help=_help) parser.add_argument("--minx", dest="minx", metavar='INT', type=int, help=_help)
@@ -287,5 +304,6 @@ def main():
args.spacex_icon, args.spacey_icon, args.spacex_icon, args.spacey_icon,
) )
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -67,5 +67,6 @@ def main():
icondata_to_png(file_src, file_dst) icondata_to_png(file_src, file_dst)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -56,19 +56,19 @@ def check_commandline():
""" """
import sys import sys
# Usage # Usage
if len(sys.argv)==1 or len(sys.argv)>3: if len(sys.argv) == 1 or len(sys.argv) > 3:
usage() usage()
if sys.argv[1] == '-h': if sys.argv[1] == '-h':
help() help()
elif not sys.argv[1].endswith((".txt", ".py")): elif not sys.argv[1].endswith((".txt", ".py")):
print ('\nBad input file extension... exiting.') print('\nBad input file extension... exiting.')
usage() usage()
else: else:
inputfile = sys.argv[1] inputfile = sys.argv[1]
if len(sys.argv) == 2: if len(sys.argv) == 2:
sort_priority = default_sort_choice sort_priority = default_sort_choice
print ('\nSecond parameter missing: choosing to order by %s.' % font_bold(sort_priority)) print('\nSecond parameter missing: choosing to order by %s.' % font_bold(sort_priority))
elif len(sys.argv)==3: elif len(sys.argv) == 3:
sort_priority = sys.argv[2] sort_priority = sys.argv[2]
if sort_priority not in sort_choices: if sort_priority not in sort_choices:
print('\nWrong sort_priority... exiting.') print('\nWrong sort_priority... exiting.')
@@ -93,9 +93,11 @@ def check_prefix(prop, btype):
return "" return ""
def check_if_changed(a,b): def check_if_changed(a, b):
if a != b: return 'changed' if a != b:
else: return 'same' return 'changed'
else:
return 'same'
def get_props_from_txt(input_filename): def get_props_from_txt(input_filename):
@@ -103,12 +105,12 @@ def get_props_from_txt(input_filename):
If the file is *.txt, the script assumes it is formatted as outlined in this script docstring If the file is *.txt, the script assumes it is formatted as outlined in this script docstring
""" """
file=open(input_filename,'r') file = open(input_filename, 'r')
file_lines=file.readlines() file_lines = file.readlines()
file.close() file.close()
props_list=[] props_list = []
props_length_max=[0,0,0,0,0,0,0,0] props_length_max = [0, 0, 0, 0, 0, 0, 0, 0]
done_text = "+" done_text = "+"
done = 0 done = 0
@@ -117,7 +119,7 @@ def get_props_from_txt(input_filename):
for iii, line in enumerate(file_lines): for iii, line in enumerate(file_lines):
# debug # debug
#print(line) # print(line)
line_strip = line.strip() line_strip = line.strip()
# empty line or comment # empty line or comment
if not line_strip: if not line_strip:
@@ -136,7 +138,7 @@ def get_props_from_txt(input_filename):
if '*' in bclass: if '*' in bclass:
comment, bclass = [x.strip() for x in bclass.split('*', 1)] comment, bclass = [x.strip() for x in bclass.split('*', 1)]
else: else:
comment= '' comment = ''
# skipping the header if we have one. # skipping the header if we have one.
# the header is assumed to be "NOTE * CLASS.FROM -> TO: TYPE DESCRIPTION" # the header is assumed to be "NOTE * CLASS.FROM -> TO: TYPE DESCRIPTION"
@@ -155,7 +157,7 @@ def get_props_from_txt(input_filename):
# make life easy and strip quotes # make life easy and strip quotes
description = description.replace("'", "").replace('"', "").replace("\\", "").strip() description = description.replace("'", "").replace('"', "").replace("\\", "").strip()
except ValueError: except ValueError:
btype, description = [tail,'NO DESCRIPTION'] btype, description = [tail, 'NO DESCRIPTION']
# keyword-check # keyword-check
kwcheck = check_prefix(bto, btype) kwcheck = check_prefix(bto, btype)
@@ -164,17 +166,17 @@ def get_props_from_txt(input_filename):
changed = check_if_changed(bfrom, bto) changed = check_if_changed(bfrom, bto)
# lists formatting # lists formatting
props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description] props = [comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
props_list.append(props) props_list.append(props)
props_length_max=list(map(max,zip(props_length_max,list(map(len,props))))) props_length_max = list(map(max, zip(props_length_max, list(map(len, props)))))
if done_text in comment: if done_text in comment:
done += 1 done += 1
tot += 1 tot += 1
print("Total done %.2f" % (done / tot * 100.0) ) print("Total done %.2f" % (done / tot * 100.0))
return (props_list,props_length_max) return (props_list, props_length_max)
def get_props_from_py(input_filename): def get_props_from_py(input_filename):
@@ -185,25 +187,25 @@ def get_props_from_py(input_filename):
# adds the list "rna_api" to this function's scope # adds the list "rna_api" to this function's scope
rna_api = __import__(input_filename[:-3]).rna_api rna_api = __import__(input_filename[:-3]).rna_api
props_length_max = [0 for i in rna_api[0]] # this way if the vector will take more elements we are safe props_length_max = [0 for i in rna_api[0]] # this way if the vector will take more elements we are safe
for index,props in enumerate(rna_api): for index, props in enumerate(rna_api):
comment, changed, bclass, bfrom, bto, kwcheck, btype, description = props comment, changed, bclass, bfrom, bto, kwcheck, btype, description = props
kwcheck = check_prefix(bto, btype) # keyword-check kwcheck = check_prefix(bto, btype) # keyword-check
changed = check_if_changed(bfrom, bto) # changed? changed = check_if_changed(bfrom, bto) # changed?
description = repr(description) description = repr(description)
description = description.replace("'", "").replace('"', "").replace("\\", "").strip() description = description.replace("'", "").replace('"', "").replace("\\", "").strip()
rna_api[index] = [comment, changed, bclass, bfrom, bto, kwcheck, btype, description] rna_api[index] = [comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
props_length = list(map(len,props)) # lengths props_length = list(map(len, props)) # lengths
props_length_max = list(map(max,zip(props_length_max,props_length))) # max lengths props_length_max = list(map(max, zip(props_length_max, props_length))) # max lengths
return (rna_api,props_length_max) return (rna_api, props_length_max)
def get_props(input_filename): def get_props(input_filename):
if input_filename.endswith(".txt"): if input_filename.endswith(".txt"):
props_list,props_length_max = get_props_from_txt(input_filename) props_list, props_length_max = get_props_from_txt(input_filename)
elif input_filename.endswith(".py"): elif input_filename.endswith(".py"):
props_list,props_length_max = get_props_from_py(input_filename) props_list, props_length_max = get_props_from_py(input_filename)
return (props_list,props_length_max) return (props_list, props_length_max)
def sort(props_list, sort_priority): def sort(props_list, sort_priority):
@@ -222,7 +224,7 @@ def sort(props_list, sort_priority):
else: else:
props_list = sorted(props_list, key=lambda p: p[i]) props_list = sorted(props_list, key=lambda p: p[i])
print ('\nSorted by %s.' % font_bold(sort_priority)) print('\nSorted by %s.' % font_bold(sort_priority))
return props_list return props_list
@@ -250,30 +252,35 @@ def write_files(basename, props_list, props_length_max):
* rna_api.py: unformatted, just as final output * rna_api.py: unformatted, just as final output
""" """
f_rna = open("rna_api.py",'w') f_rna = open("rna_api.py", 'w')
f_txt = open(basename + '_work.txt','w') f_txt = open(basename + '_work.txt', 'w')
f_py = open(basename + '_work.py','w') f_py = open(basename + '_work.py', 'w')
# reminder: props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description] # reminder: props=[comment, changed, bclass, bfrom, bto, kwcheck, btype, description]
# [comment *] ToolSettings.snap_align_rotation -> use_snap_align_rotation: boolean [Align rotation with the snapping target] # [comment *] ToolSettings.snap_align_rotation -> use_snap_align_rotation: boolean [Align rotation with the snapping target]
rna = py = txt = '' rna = py = txt = ''
props_list = [['NOTE', 'CHANGED', 'CLASS', 'FROM', 'TO', 'KEYWORD-CHECK', 'TYPE', 'DESCRIPTION']] + props_list props_list = [['NOTE', 'CHANGED', 'CLASS', 'FROM', 'TO', 'KEYWORD-CHECK', 'TYPE', 'DESCRIPTION']] + props_list
for props in props_list: for props in props_list:
#txt # txt
# quick way we can tell if it changed # quick way we can tell if it changed
if props[3] == props[4]: txt += "#" if props[3] == props[4]:
else: txt += " " txt += "#"
else:
txt += " "
if props[0] != '': txt += '%s * ' % props[0] # comment if props[0] != '':
txt += '%s.%s -> %s: %s "%s"\n' % tuple(props[2:5] + props[6:]) # skipping keyword-check txt += '%s * ' % props[0] # comment
txt += '%s.%s -> %s: %s "%s"\n' % tuple(props[2:5] + props[6:]) # skipping keyword-check
# rna_api # rna_api
if props[0] == 'NOTE': indent = '# ' if props[0] == 'NOTE':
else: indent = ' ' indent = '# '
rna += indent + '("%s", "%s", "%s", "%s", "%s"),\n' % tuple(props[2:5] + props[6:]) # description is already string formatted else:
indent = ' '
rna += indent + '("%s", "%s", "%s", "%s", "%s"),\n' % tuple(props[2:5] + props[6:]) # description is already string formatted
# py # py
blanks = [' '* (x[0]-x[1]) for x in zip(props_length_max,list(map(len,props)))] blanks = [' ' * (x[0] - x[1]) for x in zip(props_length_max, list(map(len, props)))]
props = [('"%s"%s' if props[-1] != x[0] else "%s%s") % (x[0],x[1]) for x in zip(props,blanks)] props = [('"%s"%s' if props[-1] != x[0] else "%s%s") % (x[0], x[1]) for x in zip(props, blanks)]
py += indent + '(%s, %s, %s, %s, %s, %s, %s, "%s"),\n' % tuple(props) py += indent + '(%s, %s, %s, %s, %s, %s, %s, "%s"),\n' % tuple(props)
f_txt.write(txt) f_txt.write(txt)
@@ -290,7 +297,7 @@ def write_files(basename, props_list, props_length_max):
f_py.close() f_py.close()
f_rna.close() f_rna.close()
print ('\nSaved %s, %s and %s.\n' % (font_bold(f_txt.name), font_bold(f_py.name), font_bold(f_rna.name) ) ) print('\nSaved %s, %s and %s.\n' % (font_bold(f_txt.name), font_bold(f_py.name), font_bold(f_rna.name)))
def main(): def main():
@@ -298,21 +305,21 @@ def main():
global sort_choices, default_sort_choice global sort_choices, default_sort_choice
global kw_prefixes, kw global kw_prefixes, kw
sort_choices = ['note','changed','class','from','to','kw', 'class.to'] sort_choices = ['note', 'changed', 'class', 'from', 'to', 'kw', 'class.to']
default_sort_choice = sort_choices[-1] default_sort_choice = sort_choices[-1]
kw_prefixes = [ 'active','apply','bl','exclude','has','invert','is','lock', \ kw_prefixes = ['active', 'apply', 'bl', 'exclude', 'has', 'invert', 'is', 'lock',
'pressed','show','show_only','use','use_only','layers','states', 'select'] 'pressed', 'show', 'show_only', 'use', 'use_only', 'layers', 'states', 'select']
kw = ['active','hide','invert','select','layers','mute','states','use','lock'] kw = ['active', 'hide', 'invert', 'select', 'layers', 'mute', 'states', 'use', 'lock']
input_filename, sort_priority = check_commandline() input_filename, sort_priority = check_commandline()
props_list,props_length_max = get_props(input_filename) props_list, props_length_max = get_props(input_filename)
props_list = sort(props_list,sort_priority) props_list = sort(props_list, sort_priority)
output_basename = file_basename(input_filename) output_basename = file_basename(input_filename)
write_files(output_basename, props_list,props_length_max) write_files(output_basename, props_list, props_length_max)
if __name__=='__main__': if __name__ == '__main__':
import sys import sys
if not sys.version.startswith("3"): if not sys.version.startswith("3"):
print("Incorrect python version, use python 3!") print("Incorrect python version, use python 3!")

View File

@@ -6,56 +6,58 @@ import sys
Example usage: Example usage:
python3 rna_cleaner_merge.py out_work.py rna_booleans_work.py python3 rna_cleaner_merge.py out_work.py rna_booleans_work.py
''' '''
def main(): def main():
def work_line_id(line): def work_line_id(line):
return line[2].split("|")[-1], line[3] # class/from return line[2].split("|")[-1], line[3] # class/from
if not (sys.argv[-1].endswith(".py") and sys.argv[-2].endswith(".py")):
print("Only accepts 2 py files as arguments.")
if not (sys.argv[-1].endswith(".py") and sys.argv[-2].endswith(".py")): sys.path.insert(0, ".")
print("Only accepts 2 py files as arguments.")
sys.path.insert(0, ".") mod_from = __import__(sys.argv[-1][:-3])
mod_to = __import__(sys.argv[-2][:-3])
mod_from = __import__(sys.argv[-1][:-3]) mod_to_dict = dict([(work_line_id(line), line) for line in mod_to.rna_api])
mod_to = __import__(sys.argv[-2][:-3]) mod_from_dict = dict([(work_line_id(line), line) for line in mod_from.rna_api])
mod_to_dict = dict([(work_line_id(line), line) for line in mod_to.rna_api]) rna_api_new = []
mod_from_dict = dict([(work_line_id(line), line) for line in mod_from.rna_api])
rna_api_new = [] for key, val_orig in mod_to_dict.items():
try:
val_new = mod_from_dict.pop(key)
except:
# print("not found", key)
val_new = val_orig
for key, val_orig in mod_to_dict.items(): # always take the class from the base
try: val = list(val_orig)
val_new = mod_from_dict.pop(key) val[0] = val_new[0] # comment
except: val[4] = val_new[4] # -> to
# print("not found", key) val = tuple(val)
val_new = val_orig rna_api_new.append(val)
# always take the class from the base def write_work_file(file_path, rna_api):
val = list(val_orig) rna_api = list(rna_api)
val[0] = val_new[0] # comment rna_api.sort(key=work_line_id)
val[4] = val_new[4] # -> to file_out = open(file_path, "w")
val = tuple(val) file_out.write("rna_api = [\n")
rna_api_new.append(val) for line in rna_api:
file_out.write(" %s,\n" % (repr(line)))
file_out.write("]\n")
file_out.close()
def write_work_file(file_path, rna_api): file_path = sys.argv[-2][:-3] + "_merged.py"
rna_api = list(rna_api) write_work_file(file_path, rna_api_new)
rna_api.sort(key=work_line_id)
file_out = open(file_path, "w")
file_out.write("rna_api = [\n")
for line in rna_api:
file_out.write(" %s,\n" % (repr(line)))
file_out.write("]\n")
file_out.close()
file_path = sys.argv[-2][:-3] + "_merged.py" if mod_from_dict:
write_work_file(file_path, rna_api_new) file_path = sys.argv[-2][:-3] + "_lost.py"
write_work_file(file_path, list(mod_from_dict.values()))
print("Warning '%s' contains lost %d items from module %s.py" % (file_path, len(mod_from_dict), mod_from.__name__))
if mod_from_dict:
file_path = sys.argv[-2][:-3] + "_lost.py"
write_work_file(file_path, list(mod_from_dict.values()))
print("Warning '%s' contains lost %d items from module %s.py" % (file_path, len(mod_from_dict), mod_from.__name__))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -129,6 +129,7 @@ def seek(r, txt, recurs):
newtxt = txt + '[' + str(i) + ']' newtxt = txt + '[' + str(i) + ']'
seek(r[i], newtxt, recurs + 1) seek(r[i], newtxt, recurs + 1)
seek(bpy.data, 'bpy.data', 0) seek(bpy.data, 'bpy.data', 0)
# seek(bpy.types, 'bpy.types', 0) # seek(bpy.types, 'bpy.types', 0)
''' '''
@@ -140,8 +141,8 @@ for d in dir(bpy.types):
seek(r, 'bpy.types.' + d + '.bl_rna', 0) seek(r, 'bpy.types.' + d + '.bl_rna', 0)
''' '''
#print dir(bpy) # print dir(bpy)
#import sys #import sys
#sys.exit() # sys.exit()
print("iter over ", seek_count, "rna items") print("iter over ", seek_count, "rna items")

View File

@@ -50,8 +50,10 @@ for d in defs.split('\n'):
if not w: if not w:
continue continue
try: w.remove("#define") try:
except: pass w.remove("#define")
except:
pass
# print w # print w

View File

@@ -142,5 +142,6 @@ def main():
else: else:
print("\nnone found!") print("\nnone found!")
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@@ -33,7 +33,6 @@ from modules.test_utils import (with_tempdir,
) )
class AbcPropError(Exception): class AbcPropError(Exception):
"""Raised when AbstractAlembicTest.abcprop() finds an error.""" """Raised when AbstractAlembicTest.abcprop() finds an error."""

View File

@@ -107,7 +107,6 @@ class SimpleImportTest(AbstractAlembicTest):
self.assertAlmostEqual(0, y) self.assertAlmostEqual(0, y)
self.assertAlmostEqual(2, z) self.assertAlmostEqual(2, z)
def test_select_after_import(self): def test_select_after_import(self):
# Add a sphere, so that there is something in the scene, selected, and active, # Add a sphere, so that there is something in the scene, selected, and active,
# before we do the Alembic import. # before we do the Alembic import.

View File

@@ -33,7 +33,7 @@ import imp
BLACKLIST_DIRS = ( BLACKLIST_DIRS = (
os.path.join(bpy.utils.resource_path('USER'), "scripts"), os.path.join(bpy.utils.resource_path('USER'), "scripts"),
) + tuple(addon_utils.paths()[1:]) ) + tuple(addon_utils.paths()[1:])
BLACKLIST_ADDONS = set() BLACKLIST_ADDONS = set()
@@ -54,9 +54,10 @@ def _init_addon_blacklist():
def addon_modules_sorted(): def addon_modules_sorted():
modules = addon_utils.modules({}) modules = addon_utils.modules({})
modules[:] = [ modules[:] = [
mod for mod in modules mod for mod in modules
if not (mod.__file__.startswith(BLACKLIST_DIRS)) if not (mod.__file__.startswith(BLACKLIST_DIRS))
if not (mod.__name__ in BLACKLIST_ADDONS)] if not (mod.__name__ in BLACKLIST_ADDONS)
]
modules.sort(key=lambda mod: mod.__name__) modules.sort(key=lambda mod: mod.__name__)
return modules return modules

View File

@@ -39,20 +39,20 @@ BLACKLIST = {
# The unpacked wheel is only loaded when actually used, not directly on import: # The unpacked wheel is only loaded when actually used, not directly on import:
os.path.join("io_blend_utils", "blender_bam-unpacked.whl"), os.path.join("io_blend_utils", "blender_bam-unpacked.whl"),
} }
# Some modules need to add to the `sys.path`. # Some modules need to add to the `sys.path`.
MODULE_SYS_PATHS = { MODULE_SYS_PATHS = {
# Runs in a Python subprocess, so its expected its basedir can be imported. # Runs in a Python subprocess, so its expected its basedir can be imported.
"io_blend_utils.blendfile_pack": ".", "io_blend_utils.blendfile_pack": ".",
} }
if not bpy.app.build_options.freestyle: if not bpy.app.build_options.freestyle:
BLACKLIST.add("render_freestyle_svg") BLACKLIST.add("render_freestyle_svg")
BLACKLIST_DIRS = ( BLACKLIST_DIRS = (
os.path.join(bpy.utils.resource_path('USER'), "scripts"), os.path.join(bpy.utils.resource_path('USER'), "scripts"),
) + tuple(addon_utils.paths()[1:]) ) + tuple(addon_utils.paths()[1:])
def module_names_recursive(mod_dir, *, parent=None): def module_names_recursive(mod_dir, *, parent=None):
@@ -168,7 +168,7 @@ def load_modules():
os.sep + "presets" + os.sep, os.sep + "presets" + os.sep,
os.sep + "templates" + os.sep, os.sep + "templates" + os.sep,
] + ([(os.sep + f + os.sep) for f in BLACKLIST] + ] + ([(os.sep + f + os.sep) for f in BLACKLIST] +
[(os.sep + f + ".py") for f in BLACKLIST]) [(os.sep + f + ".py") for f in BLACKLIST])
# #
# now submodules # now submodules
@@ -185,7 +185,7 @@ def load_modules():
sys.path.extend([ sys.path.extend([
os.path.normpath(os.path.join(mod_dir, f)) os.path.normpath(os.path.join(mod_dir, f))
for f in MODULE_SYS_PATHS.get(mod_name_full, ()) for f in MODULE_SYS_PATHS.get(mod_name_full, ())
]) ])
try: try:
__import__(mod_name_full) __import__(mod_name_full)
@@ -248,6 +248,7 @@ def main():
load_addons() load_addons()
load_modules() load_modules()
if __name__ == "__main__": if __name__ == "__main__":
# So a python error exits(1) # So a python error exits(1)
try: try:

View File

@@ -61,11 +61,11 @@ def render_gl(context, filepath, shade):
ctx_viewport_shade(context, shade) ctx_viewport_shade(context, shade)
#~ # stop to inspect! # stop to inspect!
#~ if filepath == "test_cube_shell_solidify_subsurf_wp_wire": # if filepath == "test_cube_shell_solidify_subsurf_wp_wire":
#~ assert(0) # assert(0)
#~ else: # else:
#~ return # return
bpy.ops.render.opengl(write_still=True, bpy.ops.render.opengl(write_still=True,
view_context=True) view_context=True)
@@ -219,6 +219,7 @@ def mesh_bmesh_poly_elems(poly, elems):
vert_total = poly.loop_total vert_total = poly.loop_total
return elems[vert_start:vert_start + vert_total] return elems[vert_start:vert_start + vert_total]
def mesh_bmesh_poly_vertices(poly): def mesh_bmesh_poly_vertices(poly):
return [loop.vertex_index return [loop.vertex_index
for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)] for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)]
@@ -505,7 +506,7 @@ cube_like_vertices = (
(-1, 1, 3), (-1, 1, 3),
(0, 1, 3), (0, 1, 3),
(0, 0, 3), (0, 0, 3),
) )
cube_like_faces = ( cube_like_faces = (
@@ -547,7 +548,7 @@ cube_like_faces = (
(31, 30, 36, 33), (31, 30, 36, 33),
(32, 31, 33, 34), (32, 31, 33, 34),
(35, 34, 33, 36), (35, 34, 33, 36),
) )
# useful since its a shell for solidify and it can be mirrored # useful since its a shell for solidify and it can be mirrored
@@ -564,7 +565,7 @@ cube_shell_vertices = (
(0, -1, 0), (0, -1, 0),
(0, 0, -1), (0, 0, -1),
(0, 1, -1), (0, 1, -1),
) )
cube_shell_face = ( cube_shell_face = (
@@ -577,7 +578,7 @@ cube_shell_face = (
(6, 5, 11), (6, 5, 11),
(7, 4, 9, 8), (7, 4, 9, 8),
(10, 7, 6, 11), (10, 7, 6, 11),
) )
def make_cube(scene): def make_cube(scene):
@@ -678,59 +679,77 @@ def make_monkey_extra(scene):
global_tests = [] global_tests = []
global_tests.append(("none", global_tests.append(
(), ("none",
)) (),
)
)
# single # single
global_tests.append(("subsurf_single", global_tests.append(
((modifier_subsurf_add, dict(levels=2)), ), ("subsurf_single",
)) ((modifier_subsurf_add, dict(levels=2)), ),
)
)
global_tests.append(
("armature_single",
((modifier_armature_add, dict()), ),
)
)
global_tests.append(("armature_single", global_tests.append(
((modifier_armature_add, dict()), ), ("mirror_single",
)) ((modifier_mirror_add, dict()), ),
)
)
global_tests.append(
("hook_single",
((modifier_hook_add, dict()), ),
)
)
global_tests.append(("mirror_single", global_tests.append(
((modifier_mirror_add, dict()), ), ("decimate_single",
)) ((modifier_decimate_add, dict()), ),
)
)
global_tests.append(("hook_single", global_tests.append(
((modifier_hook_add, dict()), ), ("build_single",
)) ((modifier_build_add, dict()), ),
)
)
global_tests.append(("decimate_single", global_tests.append(
((modifier_decimate_add, dict()), ), ("mask_single",
)) ((modifier_mask_add, dict()), ),
)
global_tests.append(("build_single", )
((modifier_build_add, dict()), ),
))
global_tests.append(("mask_single",
((modifier_mask_add, dict()), ),
))
# combinations # combinations
global_tests.append(("mirror_subsurf", global_tests.append(
((modifier_mirror_add, dict()), ("mirror_subsurf",
(modifier_subsurf_add, dict(levels=2))), ((modifier_mirror_add, dict()),
)) (modifier_subsurf_add, dict(levels=2))),
)
)
global_tests.append(("solidify_subsurf", global_tests.append(
((modifier_solidify_add, dict()), ("solidify_subsurf",
(modifier_subsurf_add, dict(levels=2))), ((modifier_solidify_add, dict()),
)) (modifier_subsurf_add, dict(levels=2))),
)
)
def apply_test(test, scene, obj, def apply_test(
render_func=None, test, scene, obj,
render_args=None, render_func=None,
render_kwargs=None, render_args=None,
): render_kwargs=None,
):
test_name, test_funcs = test test_name, test_funcs = test
@@ -756,10 +775,12 @@ def test_cube(context, test):
obj = make_cube_extra(scene) obj = make_cube_extra(scene)
ctx_camera_setup(context, location=(3, 3, 3)) ctx_camera_setup(context, location=(3, 3, 3))
apply_test(test, scene, obj, apply_test(
render_func=render_gl_all_modes, test, scene, obj,
render_args=(context, obj), render_func=render_gl_all_modes,
render_kwargs=dict(filepath=whoami())) render_args=(context, obj),
render_kwargs=dict(filepath=whoami())
)
def test_cube_like(context, test): def test_cube_like(context, test):
@@ -767,10 +788,12 @@ def test_cube_like(context, test):
obj = make_cube_like_extra(scene) obj = make_cube_like_extra(scene)
ctx_camera_setup(context, location=(5, 5, 5)) ctx_camera_setup(context, location=(5, 5, 5))
apply_test(test, scene, obj, apply_test(
render_func=render_gl_all_modes, test, scene, obj,
render_args=(context, obj), render_func=render_gl_all_modes,
render_kwargs=dict(filepath=whoami())) render_args=(context, obj),
render_kwargs=dict(filepath=whoami())
)
def test_cube_shell(context, test): def test_cube_shell(context, test):
@@ -778,10 +801,12 @@ def test_cube_shell(context, test):
obj = make_cube_shell_extra(scene) obj = make_cube_shell_extra(scene)
ctx_camera_setup(context, location=(4, 4, 4)) ctx_camera_setup(context, location=(4, 4, 4))
apply_test(test, scene, obj, apply_test(
render_func=render_gl_all_modes, test, scene, obj,
render_args=(context, obj), render_func=render_gl_all_modes,
render_kwargs=dict(filepath=whoami())) render_args=(context, obj),
render_kwargs=dict(filepath=whoami())
)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@@ -45,20 +45,20 @@ MESHES = {
( # Edges ( # Edges
), ),
( # Loops ( # Loops
0, 1, 4, 3, 0, 1, 4, 3,
3, 4, 6, 3, 4, 6,
1, 2, 5, 4, 1, 2, 5, 4,
3, 4, 6, 3, 4, 6,
4, 7, 6, 4, 7, 6,
4, 5, 9, 4, 8, 7, 4, 5, 9, 4, 8, 7,
), ),
( # Polygons ( # Polygons
(0, 4), (0, 4),
(4, 3), (4, 3),
(7, 4), (7, 4),
(11, 3), (11, 3),
(14, 3), (14, 3),
(16, 6), (16, 6),
), ),
), ),
), ),
@@ -66,17 +66,17 @@ MESHES = {
BUILTINS = ( BUILTINS = (
"primitive_plane_add", "primitive_plane_add",
"primitive_cube_add", "primitive_cube_add",
"primitive_circle_add", "primitive_circle_add",
"primitive_uv_sphere_add", "primitive_uv_sphere_add",
"primitive_ico_sphere_add", "primitive_ico_sphere_add",
"primitive_cylinder_add", "primitive_cylinder_add",
"primitive_cone_add", "primitive_cone_add",
"primitive_grid_add", "primitive_grid_add",
"primitive_monkey_add", "primitive_monkey_add",
"primitive_torus_add", "primitive_torus_add",
) )
BUILTINS_NBR = 4 BUILTINS_NBR = 4
BUILTINS_NBRCHANGES = 5 BUILTINS_NBRCHANGES = 5

View File

@@ -5,25 +5,26 @@ import unittest
from bpy.utils import units from bpy.utils import units
class UnitsTesting(unittest.TestCase): class UnitsTesting(unittest.TestCase):
# From user typing to 'internal' Blender value. # From user typing to 'internal' Blender value.
INPUT_TESTS = ( INPUT_TESTS = (
# system, type, ref, input, value # system, type, ref, input, value
##### LENGTH # LENGTH
('IMPERIAL', 'LENGTH', "", "1ft", 0.3048), ('IMPERIAL', 'LENGTH', "", "1ft", 0.3048),
('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2), ('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2),
('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4), ('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4),
('METRIC', 'LENGTH', "", "0.005µm", 0.000001 * 0.005), ('METRIC', 'LENGTH', "", "0.005µm", 0.000001 * 0.005),
('METRIC', 'LENGTH', "", "1e6km", 1000.0 * 1e6), ('METRIC', 'LENGTH', "", "1e6km", 1000.0 * 1e6),
('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5), ('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
('METRIC', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5), ('METRIC', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
# Using reference string to find a unit when none is given. # Using reference string to find a unit when none is given.
('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048), ('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048),
('METRIC', 'LENGTH', "33.3dm", "1", 0.1), ('METRIC', 'LENGTH', "33.3dm", "1", 0.1),
('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048), # ref unit is not in IMPERIAL system, default to feet... ('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048), # ref unit is not in IMPERIAL system, default to feet...
('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254), # unused ref unit, since one is given already! ('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254), # unused ref unit, since one is given already!
('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2), # default unit taken from current string (feet). ('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2), # default unit taken from current string (feet).
('METRIC', 'LENGTH', "", "1+1ft", 1.3048), # no metric units, we default to meters. ('METRIC', 'LENGTH', "", "1+1ft", 1.3048), # no metric units, we default to meters.
('IMPERIAL', 'LENGTH', "", "3+1in+1ft", 0.3048 * 4 + 0.0254), # bigger unit becomes default one! ('IMPERIAL', 'LENGTH', "", "3+1in+1ft", 0.3048 * 4 + 0.0254), # bigger unit becomes default one!
('IMPERIAL', 'LENGTH', "", "(3+1)in+1ft", 0.3048 + 0.0254 * 4), ('IMPERIAL', 'LENGTH', "", "(3+1)in+1ft", 0.3048 + 0.0254 * 4),
) )
@@ -31,18 +32,18 @@ class UnitsTesting(unittest.TestCase):
# From 'internal' Blender value to user-friendly printing # From 'internal' Blender value to user-friendly printing
OUTPUT_TESTS = ( OUTPUT_TESTS = (
# system, type, prec, sep, compat, value, output # system, type, prec, sep, compat, value, output
##### LENGTH # LENGTH
# Note: precision handling is a bit complicated when using multi-units... # Note: precision handling is a bit complicated when using multi-units...
('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"), ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"),
('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"), ('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"),
('IMPERIAL', 'LENGTH', 4, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""), ('IMPERIAL', 'LENGTH', 4, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""),
('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), ('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"),
('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), ('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"),
('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 2cm"), ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 2cm"),
('METRIC', 'LENGTH', 5, True, False, 1234.56789, "1km 234.6m"), ('METRIC', 'LENGTH', 5, True, False, 1234.56789, "1km 234.6m"),
('METRIC', 'LENGTH', 6, True, False, 1234.56789, "1km 234.57m"), ('METRIC', 'LENGTH', 6, True, False, 1234.56789, "1km 234.57m"),
('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.234568km"), ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.234568km"),
('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.123mm"), ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.123mm"),
) )
def test_units_inputs(self): def test_units_inputs(self):
@@ -63,9 +64,13 @@ class UnitsTesting(unittest.TestCase):
def test_units_outputs(self): def test_units_outputs(self):
for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS: for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS:
opt_str = units.to_string(usys, utype, val, prec, sep, compat) opt_str = units.to_string(usys, utype, val, prec, sep, compat)
self.assertEqual(opt_str, output, self.assertEqual(
msg="%s, %s: %f (precision: %d, separate units: %d, compat units: %d) => " opt_str, output,
"\"%s\", expected \"%s\"" % (usys, utype, val, prec, sep, compat, opt_str, output)) msg=(
"%s, %s: %f (precision: %d, separate units: %d, compat units: %d) => "
"\"%s\", expected \"%s\""
) % (usys, utype, val, prec, sep, compat, opt_str, output)
)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -198,6 +198,7 @@ class TestBufferProtocol(TestHelper, unittest.TestCase):
self.assertEqual(list(view1), list(view2)) self.assertEqual(list(view1), list(view2))
self.assertEqual(view1.tobytes(), view2.tobytes()) self.assertEqual(view1.tobytes(), view2.tobytes())
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])

View File

@@ -61,8 +61,10 @@ class TestClass(bpy.types.PropertyGroup):
def get_scene(lib_name, sce_name): def get_scene(lib_name, sce_name):
for s in bpy.data.scenes: for s in bpy.data.scenes:
if s.name == sce_name: if s.name == sce_name:
if (s.library and s.library.name == lib_name) or \ if (
(lib_name == None and s.library == None): (s.library and s.library.name == lib_name) or
(lib_name is None and s.library is None)
):
return s return s
@@ -309,6 +311,7 @@ def test_restrictions2():
class TestUIList(UIList): class TestUIList(UIList):
test = bpy.props.PointerProperty(type=bpy.types.Object) test = bpy.props.PointerProperty(type=bpy.types.Object)
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.prop(item, "name", text="", emboss=False, icon_value=icon) layout.prop(item, "name", text="", emboss=False, icon_value=icon)

View File

@@ -21,22 +21,22 @@ vector_data = (
(-0.854645, 0.518036, 0.033936), (-0.854645, 0.518036, 0.033936),
(0.42514, -0.437866, -0.792114), (0.42514, -0.437866, -0.792114),
(-0.358948, 0.597046, 0.717377), (-0.358948, 0.597046, 0.717377),
(-0.985413,0.144714, 0.089294), (-0.985413, 0.144714, 0.089294),
) )
# get data at different scales # get data at different scales
vector_data = sum( vector_data = sum(
(tuple(tuple(a * scale for a in v) for v in vector_data) (tuple(tuple(a * scale for a in v) for v in vector_data)
for scale in (s * sign for s in (0.0001, 0.1, 1.0, 10.0, 1000.0, 100000.0) for scale in (s * sign for s in (0.0001, 0.1, 1.0, 10.0, 1000.0, 100000.0)
for sign in (1.0, -1.0))), ()) + ((0.0, 0.0, 0.0),) for sign in (1.0, -1.0))), ()) + ((0.0, 0.0, 0.0),)
class MatrixTesting(unittest.TestCase): class MatrixTesting(unittest.TestCase):
def test_matrix_column_access(self): def test_matrix_column_access(self):
#mat = # mat =
#[ 1 2 3 4 ] # [ 1 2 3 4 ]
#[ 1 2 3 4 ] # [ 1 2 3 4 ]
#[ 1 2 3 4 ] # [ 1 2 3 4 ]
mat = Matrix(((1, 11, 111), mat = Matrix(((1, 11, 111),
(2, 22, 222), (2, 22, 222),
(3, 33, 333), (3, 33, 333),
@@ -81,11 +81,11 @@ class MatrixTesting(unittest.TestCase):
self.assertIn(item, indices) self.assertIn(item, indices)
def test_matrix_to_3x3(self): def test_matrix_to_3x3(self):
#mat = # mat =
#[ 1 2 3 4 ] # [ 1 2 3 4 ]
#[ 2 4 6 8 ] # [ 2 4 6 8 ]
#[ 3 6 9 12 ] # [ 3 6 9 12 ]
#[ 4 8 12 16 ] # [ 4 8 12 16 ]
mat = Matrix(tuple((i, 2 * i, 3 * i, 4 * i) for i in range(1, 5))) mat = Matrix(tuple((i, 2 * i, 3 * i, 4 * i) for i in range(1, 5)))
mat_correct = Matrix(((1, 2, 3), (2, 4, 6), (3, 6, 9))) mat_correct = Matrix(((1, 2, 3), (2, 4, 6), (3, 6, 9)))
self.assertEqual(mat.to_3x3(), mat_correct) self.assertEqual(mat.to_3x3(), mat_correct)
@@ -372,7 +372,6 @@ class KDTreeTesting(unittest.TestCase):
ret_filter = k_all.find(co, lambda i: (i % 2) == 0) ret_filter = k_all.find(co, lambda i: (i % 2) == 0)
self.assertAlmostEqualVector(ret_regular, ret_filter) self.assertAlmostEqualVector(ret_regular, ret_filter)
# filter out all values (search odd tree for even values and the reverse) # filter out all values (search odd tree for even values and the reverse)
co = (0,) * 3 co = (0,) * 3
ret_filter = k_odd.find(co, lambda i: (i % 2) == 0) ret_filter = k_odd.find(co, lambda i: (i % 2) == 0)

View File

@@ -8,7 +8,7 @@ DUMMY_NAME = "Untitled"
DUMMY_PATH = __file__ DUMMY_PATH = __file__
GLOBALS = { GLOBALS = {
"error_num": 0, "error_num": 0,
} }
def as_float_32(f): def as_float_32(f):
@@ -142,5 +142,6 @@ def main():
print("Error (total): %d" % GLOBALS["error_num"]) print("Error (total): %d" % GLOBALS["error_num"])
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -155,5 +155,6 @@ def main():
test_language_coverage() test_language_coverage()
test_urls() test_urls()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -36,7 +36,7 @@ RANDOM_MULTIPLY = 10
STATE = { STATE = {
"counter": 0, "counter": 0,
} }
op_blacklist = ( op_blacklist = (
@@ -91,7 +91,7 @@ op_blacklist = (
"wm.keymap_restore", # another annoying one "wm.keymap_restore", # another annoying one
"wm.addon_*", # harmless, but dont change state "wm.addon_*", # harmless, but dont change state
"console.*", # just annoying - but harmless "console.*", # just annoying - but harmless
) )
def blend_list(mainpath): def blend_list(mainpath):
@@ -114,6 +114,7 @@ def blend_list(mainpath):
return list(sorted(file_list(mainpath, is_blend))) return list(sorted(file_list(mainpath, is_blend)))
if USE_FILES: if USE_FILES:
USE_FILES_LS = blend_list(USE_FILES) USE_FILES_LS = blend_list(USE_FILES)
# print(USE_FILES_LS) # print(USE_FILES_LS)
@@ -176,7 +177,7 @@ if USE_ATTRSET:
CLS_BLACKLIST = ( CLS_BLACKLIST = (
bpy.types.BrushTextureSlot, bpy.types.BrushTextureSlot,
bpy.types.Brush, bpy.types.Brush,
) )
property_typemap = build_property_typemap(CLS_BLACKLIST) property_typemap = build_property_typemap(CLS_BLACKLIST)
bpy_struct_type = bpy.types.Struct.__base__ bpy_struct_type = bpy.types.Struct.__base__
@@ -228,7 +229,7 @@ if USE_ATTRSET:
{0: "", 1: "hello", 2: "test"}, {"": 0, "hello": 1, "test": 2}, {0: "", 1: "hello", 2: "test"}, {"": 0, "hello": 1, "test": 2},
set(), {"", "test", "."}, {None, ..., type}, set(), {"", "test", "."}, {None, ..., type},
range(10), (" " * i for i in range(10)), range(10), (" " * i for i in range(10)),
) )
def attrset_data(): def attrset_data():
for attr in dir(bpy.data): for attr in dir(bpy.data):
@@ -480,8 +481,9 @@ def main():
print("Finished %r" % __file__) print("Finished %r" % __file__)
if __name__ == "__main__": if __name__ == "__main__":
#~ for i in range(200): # ~ for i in range(200):
#~ RANDOM_SEED[0] += 1 # ~ RANDOM_SEED[0] += 1
#~ main() #~ main()
main() main()

View File

@@ -31,6 +31,7 @@ import difflib
import pathlib import pathlib
from pathlib import Path from pathlib import Path
def with_tempdir(wrapped): def with_tempdir(wrapped):
"""Creates a temporary directory for the function, cleaning up after it returns normally. """Creates a temporary directory for the function, cleaning up after it returns normally.
@@ -56,8 +57,10 @@ def with_tempdir(wrapped):
return decorator return decorator
LINE = "+----------------------------------------------------------------" LINE = "+----------------------------------------------------------------"
class AbstractColladaTest(unittest.TestCase): class AbstractColladaTest(unittest.TestCase):
@classmethod @classmethod
@@ -71,33 +74,33 @@ class AbstractColladaTest(unittest.TestCase):
ref = open(reference) ref = open(reference)
exp = open(export) exp = open(export)
diff=difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0) diff = difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0)
ref.close() ref.close()
exp.close() exp.close()
diff_count = 0; diff_count = 0
for line in diff: for line in diff:
error = True error = True
for prefix in ('---', '+++', '@@'): for prefix in ('---', '+++', '@@'):
# Ignore diff metadata # Ignore diff metadata
if line.startswith(prefix): if line.startswith(prefix):
error=False error = False
break break
else: else:
# Ignore time stamps # Ignore time stamps
for ignore in ('<created>', '<modified>', '<authoring_tool>'): for ignore in ('<created>', '<modified>', '<authoring_tool>'):
if line[1:].strip().startswith(ignore): if line[1:].strip().startswith(ignore):
error=False error = False
break break
if error: if error:
diff_count +=1 diff_count += 1
pline = line.strip() pline = line.strip()
if diff_count == 1: if diff_count == 1:
print("\n%s" % LINE) print("\n%s" % LINE)
print("|Test has errors:") print("|Test has errors:")
print(LINE) print(LINE)
pre = "reference" if pline[0] == "-" else "generated" pre = "reference" if pline[0] == "-" else "generated"
print ("| %s:%s"% (pre, pline[1:])) print("| %s:%s" % (pre, pline[1:]))
if diff_count > 0: if diff_count > 0:
print(LINE) print(LINE)
@@ -107,14 +110,16 @@ class AbstractColladaTest(unittest.TestCase):
return diff_count == 0 return diff_count == 0
class MeshExportTest4(AbstractColladaTest): class MeshExportTest4(AbstractColladaTest):
@with_tempdir @with_tempdir
def test_export_animation_suzannes_sample_matrix(self, tempdir: pathlib.Path): def test_export_animation_suzannes_sample_matrix(self, tempdir: pathlib.Path):
test = "suzannes_parent_inverse_sample_10_matrix" test = "suzannes_parent_inverse_sample_10_matrix"
reference_dae = self.testdir / Path("%s.dae" % test) reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export(filepath="%s" % str(outfile), bpy.ops.wm.collada_export(
filepath="%s" % str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@@ -142,20 +147,23 @@ class MeshExportTest4(AbstractColladaTest):
export_texture_type_selection='mat', export_texture_type_selection='mat',
open_sim=False, open_sim=False,
limit_precision=True, limit_precision=True,
keep_bind_info=False) keep_bind_info=False,
)
# Now check the resulting Collada file. # Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile): if not self.checkdae(reference_dae, outfile):
self.fail() self.fail()
class MeshExportTest3(AbstractColladaTest): class MeshExportTest3(AbstractColladaTest):
@with_tempdir @with_tempdir
def test_export_animation_suzannes_sample_locrotscale(self, tempdir: pathlib.Path): def test_export_animation_suzannes_sample_locrotscale(self, tempdir: pathlib.Path):
test = "suzannes_parent_inverse_sample_10_channels" test = "suzannes_parent_inverse_sample_10_channels"
reference_dae = self.testdir / Path("%s.dae" % test) reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export(filepath="%s" % str(outfile), bpy.ops.wm.collada_export(
filepath="%s" % str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@@ -183,20 +191,23 @@ class MeshExportTest3(AbstractColladaTest):
export_texture_type_selection='mat', export_texture_type_selection='mat',
open_sim=False, open_sim=False,
limit_precision=True, limit_precision=True,
keep_bind_info=False) keep_bind_info=False,
)
# Now check the resulting Collada file. # Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile): if not self.checkdae(reference_dae, outfile):
self.fail() self.fail()
class MeshExportTest2(AbstractColladaTest): class MeshExportTest2(AbstractColladaTest):
@with_tempdir @with_tempdir
def test_export_animation_suzannes_keyframe_matrix(self, tempdir: pathlib.Path): def test_export_animation_suzannes_keyframe_matrix(self, tempdir: pathlib.Path):
test = "suzannes_parent_inverse_keyframes_matrix" test = "suzannes_parent_inverse_keyframes_matrix"
reference_dae = self.testdir / Path("%s.dae" % test) reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export(filepath="%s" % str(outfile), bpy.ops.wm.collada_export(
filepath="%s" % str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@@ -224,20 +235,23 @@ class MeshExportTest2(AbstractColladaTest):
export_texture_type_selection='mat', export_texture_type_selection='mat',
open_sim=False, open_sim=False,
limit_precision=True, limit_precision=True,
keep_bind_info=False) keep_bind_info=False,
)
# Now check the resulting Collada file. # Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile): if not self.checkdae(reference_dae, outfile):
self.fail() self.fail()
class MeshExportTest1(AbstractColladaTest): class MeshExportTest1(AbstractColladaTest):
@with_tempdir @with_tempdir
def test_export_animation_suzannes_keyframe_locrotscale(self, tempdir: pathlib.Path): def test_export_animation_suzannes_keyframe_locrotscale(self, tempdir: pathlib.Path):
test = "suzannes_parent_inverse_keyframes_channels" test = "suzannes_parent_inverse_keyframes_channels"
reference_dae = self.testdir / Path("%s.dae" % test) reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export(filepath="%s" % str(outfile), bpy.ops.wm.collada_export(
filepath="%s" % str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type='DEFAULT', display_type='DEFAULT',
@@ -265,7 +279,8 @@ class MeshExportTest1(AbstractColladaTest):
export_texture_type_selection='mat', export_texture_type_selection='mat',
open_sim=False, open_sim=False,
limit_precision=True, limit_precision=True,
keep_bind_info=False) keep_bind_info=False,
)
# Now check the resulting Collada file. # Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile): if not self.checkdae(reference_dae, outfile):
@@ -277,4 +292,4 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--testdir', required=True) parser.add_argument('--testdir', required=True)
args, remaining = parser.parse_known_args() args, remaining = parser.parse_known_args()
unittest.main(argv=sys.argv[0:1]+remaining) unittest.main(argv=sys.argv[0:1] + remaining)

View File

@@ -31,6 +31,7 @@ import difflib
import pathlib import pathlib
from pathlib import Path from pathlib import Path
def with_tempdir(wrapped): def with_tempdir(wrapped):
"""Creates a temporary directory for the function, cleaning up after it returns normally. """Creates a temporary directory for the function, cleaning up after it returns normally.
@@ -56,8 +57,10 @@ def with_tempdir(wrapped):
return decorator return decorator
LINE = "+----------------------------------------------------------------" LINE = "+----------------------------------------------------------------"
class AbstractColladaTest(unittest.TestCase): class AbstractColladaTest(unittest.TestCase):
@classmethod @classmethod
@@ -71,33 +74,33 @@ class AbstractColladaTest(unittest.TestCase):
ref = open(reference) ref = open(reference)
exp = open(export) exp = open(export)
diff=difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0) diff = difflib.unified_diff(ref.readlines(), exp.readlines(), lineterm='', n=0)
ref.close() ref.close()
exp.close() exp.close()
diff_count = 0; diff_count = 0
for line in diff: for line in diff:
error = True error = True
for prefix in ('---', '+++', '@@'): for prefix in ('---', '+++', '@@'):
# Ignore diff metadata # Ignore diff metadata
if line.startswith(prefix): if line.startswith(prefix):
error=False error = False
break break
else: else:
# Ignore time stamps # Ignore time stamps
for ignore in ('<created>', '<modified>', '<authoring_tool>'): for ignore in ('<created>', '<modified>', '<authoring_tool>'):
if line[1:].strip().startswith(ignore): if line[1:].strip().startswith(ignore):
error=False error = False
break break
if error: if error:
diff_count +=1 diff_count += 1
pline = line.strip() pline = line.strip()
if diff_count == 1: if diff_count == 1:
print("\n%s" % LINE) print("\n%s" % LINE)
print("|Test has errors:") print("|Test has errors:")
print(LINE) print(LINE)
pre = "reference" if pline[0] == "-" else "generated" pre = "reference" if pline[0] == "-" else "generated"
print ("| %s:%s"% (pre, pline[1:])) print("| %s:%s" % (pre, pline[1:]))
if diff_count > 0: if diff_count > 0:
print(LINE) print(LINE)
@@ -107,14 +110,16 @@ class AbstractColladaTest(unittest.TestCase):
return diff_count == 0 return diff_count == 0
class MeshExportTest(AbstractColladaTest): class MeshExportTest(AbstractColladaTest):
@with_tempdir @with_tempdir
def test_export_single_mesh(self, tempdir: pathlib.Path): def test_export_single_mesh(self, tempdir: pathlib.Path):
test = "mesh_simple_001" test = "mesh_simple_001"
reference_dae = self.testdir / Path("%s.dae" % test) reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test) outfile = tempdir / Path("%s_out.dae" % test)
bpy.ops.wm.collada_export(filepath="%s" % str(outfile), bpy.ops.wm.collada_export(
filepath="%s" % str(outfile),
check_existing=True, check_existing=True,
filemode=8, filemode=8,
display_type="DEFAULT", display_type="DEFAULT",
@@ -140,15 +145,17 @@ class MeshExportTest(AbstractColladaTest):
export_texture_type_selection="mat", export_texture_type_selection="mat",
open_sim=False, open_sim=False,
limit_precision=False, limit_precision=False,
keep_bind_info=False) keep_bind_info=False,
)
# Now check the resulting Collada file. # Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile): if not self.checkdae(reference_dae, outfile):
self.fail() self.fail()
if __name__ == '__main__': if __name__ == '__main__':
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--testdir', required=True) parser.add_argument('--testdir', required=True)
args, remaining = parser.parse_known_args() args, remaining = parser.parse_known_args()
unittest.main(argv=sys.argv[0:1]+remaining) unittest.main(argv=sys.argv[0:1] + remaining)

View File

@@ -23,6 +23,7 @@ class COLORS_DUMMY:
GREEN = '' GREEN = ''
ENDC = '' ENDC = ''
COLORS = COLORS_DUMMY COLORS = COLORS_DUMMY
@@ -55,10 +56,12 @@ def blend_list(dirpath):
filepath = os.path.join(dirpath, filename) filepath = os.path.join(dirpath, filename)
yield filepath yield filepath
def test_get_name(filepath): def test_get_name(filepath):
filename = os.path.basename(filepath) filename = os.path.basename(filepath)
return os.path.splitext(filename)[0] return os.path.splitext(filename)[0]
def test_get_images(output_dir, filepath): def test_get_images(output_dir, filepath):
testname = test_get_name(filepath) testname = test_get_name(filepath)
dirpath = os.path.dirname(filepath) dirpath = os.path.dirname(filepath)
@@ -96,7 +99,7 @@ class Report:
'update', 'update',
'failed_tests', 'failed_tests',
'passed_tests' 'passed_tests'
) )
def __init__(self, title, output_dir, idiff): def __init__(self, title, output_dir, idiff):
self.title = title self.title = title
@@ -257,7 +260,6 @@ class Report:
else: else:
self.passed_tests += test_html self.passed_tests += test_html
def _diff_output(self, filepath, tmp_filepath): def _diff_output(self, filepath, tmp_filepath):
old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath) old_img, ref_img, new_img, diff_img = test_get_images(self.output_dir, filepath)
@@ -280,7 +282,7 @@ class Report:
"-failpercent", "1", "-failpercent", "1",
ref_img, ref_img,
tmp_filepath, tmp_filepath,
) )
try: try:
subprocess.check_output(command) subprocess.check_output(command)
failed = False failed = False
@@ -307,7 +309,7 @@ class Report:
"-abs", "-scale", "16", "-abs", "-scale", "16",
ref_img, ref_img,
tmp_filepath tmp_filepath
) )
try: try:
subprocess.check_output(command) subprocess.check_output(command)
@@ -317,7 +319,6 @@ class Report:
return not failed return not failed
def _run_test(self, filepath, render_cb): def _run_test(self, filepath, render_cb):
testname = test_get_name(filepath) testname = test_get_name(filepath)
print_message(testname, 'SUCCESS', 'RUN') print_message(testname, 'SUCCESS', 'RUN')
@@ -344,7 +345,7 @@ class Report:
return error return error
elif error == "NO_START": elif error == "NO_START":
print_message('Can not perform tests because blender fails to start.', print_message('Can not perform tests because blender fails to start.',
'Make sure INSTALL target was run.') 'Make sure INSTALL target was run.')
return error return error
elif error == 'VERIFY': elif error == 'VERIFY':
print_message("Rendered result is different from reference image") print_message("Rendered result is different from reference image")
@@ -354,7 +355,6 @@ class Report:
'FAILURE', 'FAILED') 'FAILURE', 'FAILED')
return error return error
def _run_all_tests(self, dirname, dirpath, render_cb): def _run_all_tests(self, dirname, dirpath, render_cb):
passed_tests = [] passed_tests = []
failed_tests = [] failed_tests = []
@@ -387,8 +387,8 @@ class Report:
'SUCCESS', 'PASSED') 'SUCCESS', 'PASSED')
if failed_tests: if failed_tests:
print_message("{} tests, listed below:" . print_message("{} tests, listed below:" .
format(len(failed_tests)), format(len(failed_tests)),
'FAILURE', 'FAILED') 'FAILURE', 'FAILED')
failed_tests.sort() failed_tests.sort()
for test in failed_tests: for test in failed_tests:
print_message("{}" . format(test), 'FAILURE', "FAILED") print_message("{}" . format(test), 'FAILURE', "FAILED")

View File

@@ -62,7 +62,6 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
blender: pathlib.Path = None blender: pathlib.Path = None
testdir: pathlib.Path = None testdir: pathlib.Path = None
def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str: def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str:
"""Runs Blender by opening a blendfile and executing a script. """Runs Blender by opening a blendfile and executing a script.
@@ -92,7 +91,7 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
'-E', 'CYCLES', '-E', 'CYCLES',
'--python-exit-code', '47', '--python-exit-code', '47',
'--python-expr', python_script, '--python-expr', python_script,
] ]
) )
proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, proc = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,

View File

@@ -8,6 +8,7 @@ import shutil
import subprocess import subprocess
import sys import sys
def screenshot(): def screenshot():
import bpy import bpy
@@ -19,6 +20,7 @@ def screenshot():
bpy.ops.wm.quit_blender() bpy.ops.wm.quit_blender()
# When run from inside Blender, take screenshot and exit. # When run from inside Blender, take screenshot and exit.
try: try:
import bpy import bpy
@@ -93,5 +95,6 @@ def main():
sys.exit(not ok) sys.exit(not ok)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -93,7 +93,7 @@ def check_files_flake8(files):
# times types are compared, # times types are compared,
# I rather keep them specific # I rather keep them specific
"E721", "E721",
) )
for f, pep8_type in files: for f, pep8_type in files:
@@ -129,10 +129,10 @@ def check_files_pylint(files):
"C0413," # import should be placed at the top "C0413," # import should be placed at the top
"W0613," # unused argument, may add this back "W0613," # unused argument, may add this back
# but happens a lot for 'context' for eg. # but happens a lot for 'context' for eg.
"W0232," # class has no __init__, Operator/Panel/Menu etc "W0232," # class has no __init__, Operator/Panel/Menu etc
"W0142," # Used * or ** magic "W0142," # Used * or ** magic
# even needed in some cases # even needed in some cases
"R0902," # Too many instance attributes "R0902," # Too many instance attributes
"R0903," # Too many statements "R0903," # Too many statements
"R0911," # Too many return statements "R0911," # Too many return statements
"R0912," # Too many branches "R0912," # Too many branches
@@ -204,6 +204,5 @@ def main():
print("Skipping pylint checks (command not found)") print("Skipping pylint checks (command not found)")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -3,7 +3,7 @@
import unittest import unittest
import random import random
test= bpy.data.test test = bpy.data.test
# farr - 1-dimensional array of float # farr - 1-dimensional array of float
# fdarr - dynamic 1-dimensional array of float # fdarr - dynamic 1-dimensional array of float
@@ -12,6 +12,7 @@ test= bpy.data.test
# same as above for other types except that the first letter is "i" for int and "b" for bool # same as above for other types except that the first letter is "i" for int and "b" for bool
class TestArray(unittest.TestCase): class TestArray(unittest.TestCase):
# test that assignment works by: assign -> test value # test that assignment works by: assign -> test value
# - rvalue = list of float # - rvalue = list of float
@@ -20,14 +21,14 @@ class TestArray(unittest.TestCase):
# bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
def setUp(self): def setUp(self):
test.farr= (1.0, 2.0, 3.0) test.farr = (1.0, 2.0, 3.0)
test.iarr= (7, 8, 9) test.iarr = (7, 8, 9)
test.barr= (False, True, False) test.barr = (False, True, False)
# test access # test access
# test slice access, negative indices # test slice access, negative indices
def test_access(self): def test_access(self):
rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False]) rvals = ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
for arr, rval in zip((test.farr, test.iarr, test.barr), rvals): for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
self.assertEqual(prop_to_list(arr), rval) self.assertEqual(prop_to_list(arr), rval)
self.assertEqual(arr[0:3], rval) self.assertEqual(arr[0:3], rval)
@@ -39,12 +40,12 @@ class TestArray(unittest.TestCase):
# fail when index out of bounds # fail when index out of bounds
def test_access_fail(self): def test_access_fail(self):
for arr in (test.farr, test.iarr, test.barr): for arr in (test.farr, test.iarr, test.barr):
self.assertRaises(IndexError, lambda : arr[4]) self.assertRaises(IndexError, lambda: arr[4])
# test assignment of a whole array # test assignment of a whole array
def test_assign_array(self): def test_assign_array(self):
# should accept int as float # should accept int as float
test.farr= (1, 2, 3) test.farr = (1, 2, 3)
# fail when: unexpected no. of items, invalid item type # fail when: unexpected no. of items, invalid item type
def test_assign_array_fail(self): def test_assign_array_fail(self):
@@ -55,20 +56,20 @@ class TestArray(unittest.TestCase):
self.assertRaises(ValueError, assign_empty_list, arr) self.assertRaises(ValueError, assign_empty_list, arr)
def assign_invalid_float(): def assign_invalid_float():
test.farr= (1.0, 2.0, "3.0") test.farr = (1.0, 2.0, "3.0")
def assign_invalid_int(): def assign_invalid_int():
test.iarr= ("1", 2, 3) test.iarr = ("1", 2, 3)
def assign_invalid_bool(): def assign_invalid_bool():
test.barr= (True, 0.123, False) test.barr = (True, 0.123, False)
for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]: for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
self.assertRaises(TypeError, func) self.assertRaises(TypeError, func)
# shouldn't accept float as int # shouldn't accept float as int
def assign_float_as_int(): def assign_float_as_int():
test.iarr= (1, 2, 3.0) test.iarr = (1, 2, 3.0)
self.assertRaises(TypeError, assign_float_as_int) self.assertRaises(TypeError, assign_float_as_int)
# non-dynamic arrays cannot change size # non-dynamic arrays cannot change size
@@ -81,14 +82,14 @@ class TestArray(unittest.TestCase):
def test_assign_item(self): def test_assign_item(self):
for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)): for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
for i in range(len(arr)): for i in range(len(arr)):
val= rand_func() val = rand_func()
arr[i] = val arr[i] = val
self.assertEqual(arr[i], val) self.assertEqual(arr[i], val)
# float prop should accept also int # float prop should accept also int
for i in range(len(test.farr)): for i in range(len(test.farr)):
val= rand_int() val = rand_int()
test.farr[i] = val test.farr[i] = val
self.assertEqual(test.farr[i], float(val)) self.assertEqual(test.farr[i], float(val))
@@ -112,7 +113,7 @@ class TestArray(unittest.TestCase):
# test various lengths here # test various lengths here
for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)): for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
for length in range(1, 64): for length in range(1, 64):
rval= make_random_array(length, rand_func) rval = make_random_array(length, rand_func)
setattr(test, arr, rval) setattr(test, arr, rval)
self.assertEqual(prop_to_list(getattr(test, arr)), rval) self.assertEqual(prop_to_list(getattr(test, arr)), rval)
@@ -136,7 +137,7 @@ class TestMArray(unittest.TestCase):
def test_assign_array(self): def test_assign_array(self):
for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
# assignment of [3][4][5] # assignment of [3][4][5]
rval= make_random_3d_array((3, 4, 5), func) rval = make_random_3d_array((3, 4, 5), func)
setattr(test, arr, rval) setattr(test, arr, rval)
self.assertEqual(prop_to_list(getattr(test, arr)), rval) self.assertEqual(prop_to_list(getattr(test, arr)), rval)
@@ -144,7 +145,7 @@ class TestMArray(unittest.TestCase):
def test_assign_array_fail(self): def test_assign_array_fail(self):
def assign_empty_array(): def assign_empty_array():
test.fmarr= () test.fmarr = ()
self.assertRaises(ValueError, assign_empty_array) self.assertRaises(ValueError, assign_empty_array)
def assign_invalid_size(arr, rval): def assign_invalid_size(arr, rval):
@@ -152,19 +153,19 @@ class TestMArray(unittest.TestCase):
# assignment of 3,4,4 or 3,3,5 should raise ex # assignment of 3,4,4 or 3,3,5 should raise ex
for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
rval= make_random_3d_array((3, 4, 4), func) rval = make_random_3d_array((3, 4, 4), func)
self.assertRaises(ValueError, assign_invalid_size, arr, rval) self.assertRaises(ValueError, assign_invalid_size, arr, rval)
rval= make_random_3d_array((3, 3, 5), func) rval = make_random_3d_array((3, 3, 5), func)
self.assertRaises(ValueError, assign_invalid_size, arr, rval) self.assertRaises(ValueError, assign_invalid_size, arr, rval)
rval= make_random_3d_array((3, 3, 3), func) rval = make_random_3d_array((3, 3, 3), func)
self.assertRaises(ValueError, assign_invalid_size, arr, rval) self.assertRaises(ValueError, assign_invalid_size, arr, rval)
def test_assign_item(self): def test_assign_item(self):
# arr[i] = x # arr[i] = x
for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2): for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
rval= make_random_2d_array((4, 5), func) rval = make_random_2d_array((4, 5), func)
for i in range(3): for i in range(3):
getattr(test, arr)[i] = rval getattr(test, arr)[i] = rval
@@ -173,23 +174,22 @@ class TestMArray(unittest.TestCase):
# arr[i][j] = x # arr[i][j] = x
for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2): for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
arr= getattr(test, arr) arr = getattr(test, arr)
rval= make_random_array(5, func) rval = make_random_array(5, func)
for i in range(3): for i in range(3):
for j in range(4): for j in range(4):
arr[i][j] = rval arr[i][j] = rval
self.assertEqual(prop_to_list(arr[i][j]), rval) self.assertEqual(prop_to_list(arr[i][j]), rval)
def test_assign_item_fail(self): def test_assign_item_fail(self):
def assign_wrong_size(arr, i, rval): def assign_wrong_size(arr, i, rval):
getattr(test, arr)[i] = rval getattr(test, arr)[i] = rval
# assign wrong size at level 2 # assign wrong size at level 2
for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
rval1= make_random_2d_array((3, 5), func) rval1 = make_random_2d_array((3, 5), func)
rval2= make_random_2d_array((4, 3), func) rval2 = make_random_2d_array((4, 3), func)
for i in range(3): for i in range(3):
self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1) self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
@@ -198,22 +198,22 @@ class TestMArray(unittest.TestCase):
def test_dynamic_assign_array(self): def test_dynamic_assign_array(self):
for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)): for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
# assignment of [3][4][5] # assignment of [3][4][5]
rval= make_random_3d_array((3, 4, 5), func) rval = make_random_3d_array((3, 4, 5), func)
setattr(test, arr, rval) setattr(test, arr, rval)
self.assertEqual(prop_to_list(getattr(test, arr)), rval) self.assertEqual(prop_to_list(getattr(test, arr)), rval)
# [2][4][5] # [2][4][5]
rval= make_random_3d_array((2, 4, 5), func) rval = make_random_3d_array((2, 4, 5), func)
setattr(test, arr, rval) setattr(test, arr, rval)
self.assertEqual(prop_to_list(getattr(test, arr)), rval) self.assertEqual(prop_to_list(getattr(test, arr)), rval)
# [1][4][5] # [1][4][5]
rval= make_random_3d_array((1, 4, 5), func) rval = make_random_3d_array((1, 4, 5), func)
setattr(test, arr, rval) setattr(test, arr, rval)
self.assertEqual(prop_to_list(getattr(test, arr)), rval) self.assertEqual(prop_to_list(getattr(test, arr)), rval)
# test access # test access
def test_access(self): def test_access(self):
pass pass
@@ -221,26 +221,32 @@ class TestMArray(unittest.TestCase):
def test_access_fail(self): def test_access_fail(self):
pass pass
random.seed() random.seed()
def rand_int(): def rand_int():
return random.randint(-1000, 1000) return random.randint(-1000, 1000)
def rand_float(): def rand_float():
return float(rand_int()) return float(rand_int())
def rand_bool(): def rand_bool():
return bool(random.randint(0, 1)) return bool(random.randint(0, 1))
def make_random_array(len, rand_func): def make_random_array(len, rand_func):
arr= [] arr = []
for i in range(len): for i in range(len):
arr.append(rand_func()) arr.append(rand_func())
return arr return arr
def make_random_2d_array(dimsize, rand_func): def make_random_2d_array(dimsize, rand_func):
marr= [] marr = []
for i in range(dimsize[0]): for i in range(dimsize[0]):
marr.append([]) marr.append([])
@@ -249,8 +255,9 @@ def make_random_2d_array(dimsize, rand_func):
return marr return marr
def make_random_3d_array(dimsize, rand_func): def make_random_3d_array(dimsize, rand_func):
marr= [] marr = []
for i in range(dimsize[0]): for i in range(dimsize[0]):
marr.append([]) marr.append([])
@@ -262,8 +269,9 @@ def make_random_3d_array(dimsize, rand_func):
return marr return marr
def prop_to_list(prop): def prop_to_list(prop):
ret= [] ret = []
for x in prop: for x in prop:
if type(x) not in {bool, int, float}: if type(x) not in {bool, int, float}:
@@ -273,8 +281,10 @@ def prop_to_list(prop):
return ret return ret
def suite(): def suite():
return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)]) return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
if __name__ == "__main__": if __name__ == "__main__":
unittest.TextTestRunner(verbosity=2).run(suite()) unittest.TextTestRunner(verbosity=2).run(suite())