Source code for pdbx.writer

##
# File: PdbxWriter.py
# Date: 2011-10-09 Jdw Adapted from PdbxParser.py
#
# Updates:
# 5-Apr-2011 jdw Using the double quote format preference
# 23-Oct-2012 jdw update path details and reorganize.
#
###
"""Classes for writing data and dictionary containers in PDBx/mmCIF format."""
from sys import stdout
from .containers import DefinitionContainer, DataContainer
from .errors import PdbxError

__docformat__ = "restructuredtext en"
__author__ = "John Westbrook"
__email__ = "jwest@rcsb.rutgers.edu"


MAXIMUM_LINE_LENGTH = 2048
SPACING = 2
INDENT_DEFINITION = 3
DO_DEFINITION_INDENT = False


[docs]class PdbxWriter: """Write PDBx data files or dictionaries. Use the input container or container list. """ def __init__(self, output_file=stdout): """Initialize. :param file output_file: file object ready for writing """ self.__output_file = output_file self.__container_list = [] self.__maximum_line_length = MAXIMUM_LINE_LENGTH self.__spacing = SPACING self.__indent_definition = INDENT_DEFINITION self.__indent_space = " " * self.__indent_definition self._do_definition_indent = DO_DEFINITION_INDENT # Maximum number of rows checked for value length and format self.__row_partition = None
[docs] def set_row_partition(self, num_rows): """Maximum number of rows checked for value length and format. :param int num_rows: maximum number of rows """ self.__row_partition = num_rows
[docs] def write(self, container_list): """Write out a list of containers. :param list container_list: list of :class:`~pdbx.containers.ContainerBase` objects to write. """ self.__container_list = container_list for container in self.__container_list: self.write_container(container)
[docs] def write_container(self, container): """Write out information for an individual container. :param container: container to write :type container: :class:`~pdbx.containers.ContainerBase` """ indent_string = " " * self.__indent_definition if isinstance(container, DefinitionContainer): self.__write("save_%s\n" % container.name) self._do_definition_indent = True self.__write(indent_string + "#\n") elif isinstance(container, DataContainer): if container.get_global(): self.__write("global_\n") self._do_definition_indent = False self.__write("\n") else: self.__write("data_%s\n" % container.name) self._do_definition_indent = False self.__write("#\n") for name in container.get_object_name_list(): obj = container.get_object(name) object_list = obj.row_list # Skip empty objects if not object_list: continue # Item - value formattting if len(object_list) == 1: self.__write_item_value_format(obj) # Table formatting elif len(object_list) > 1 and obj.attribute_list: self.__write_table_format(obj) else: raise PdbxError( "len(object_list) = %d and len(obj.attribute_list) = %d" % (len(object_list), len(obj.attribute_list)) ) if self._do_definition_indent: self.__write(indent_string + "#") else: self.__write("#") # Add a trailing saveframe reserved word if isinstance(container, DefinitionContainer): self.__write("\nsave_\n") self.__write("#\n")
def __write(self, string_): """Write a string. :param str string_: string to write """ self.__output_file.write(string_) def __write_item_value_format(self, category): """Write items and values for the given category. :param category: category to write :type category: :class:`~pdbx.containers.DataCategory` """ # Compute the maximum item name length within this category - attribute_name_max_length = 0 for attribute_name in category.attribute_list: attribute_name_max_length = max( attribute_name_max_length, len(attribute_name) ) item_name_max_length = ( self.__spacing + len(category.name) + attribute_name_max_length + 2 ) line_list = [] line_list.append("#\n") for attribute_name, _ in category.attribute_list_with_order: if self._do_definition_indent: # - add indent -- line_list.append(self.__indent_space) item_name = "_%s.%s" % (category.name, attribute_name) line_list.append(item_name.ljust(item_name_max_length)) line_list.append(category.get_value_formatted(attribute_name, 0)) line_list.append("\n") self.__write("".join(line_list)) def __write_table_format(self, category): """Write table format data. :param category: category to write :type category: :class:`~pdbx.containers.DataCategory` """ # Write the declaration of the loop_ line_list = [] line_list.append("#\n") if self._do_definition_indent: line_list.append(self.__indent_space) line_list.append("loop_") for attribute_name in category.attribute_list: line_list.append("\n") if self._do_definition_indent: line_list.append(self.__indent_space) item_name = "_%s.%s" % (category.name, attribute_name) line_list.append(item_name) self.__write("".join(line_list)) # Write the data in tabular format # For speed make the following evaluation on a portion of the table if self.__row_partition is not None: num_steps = max(1, category.row_count / self.__row_partition) else: num_steps = 1 format_type_list, _ = category.get_format_type_list(steps=num_steps) max_length_list = category.get_max_attribute_list_length( steps=num_steps ) spacing = " " * self.__spacing for irow in range(category.row_count): line_list = [] line_list.append("\n") if self._do_definition_indent: line_list.append(self.__indent_space + " ") for iattr in range(category.attribute_count): format_type = format_type_list[iattr] max_length = max_length_list[iattr] if format_type in ("FT_UNQUOTED_STRING", "FT_NULL_VALUE"): val = category.get_value_formatted_by_index(iattr, irow) line_list.append(val.ljust(max_length)) elif format_type == "FT_NUMBER": val = category.get_value_formatted_by_index(iattr, irow) line_list.append(val.rjust(max_length)) elif format_type == "FT_QUOTED_STRING": val = category.get_value_formatted_by_index(iattr, irow) line_list.append(val.ljust(max_length + 2)) elif format_type == "FT_MULTI_LINE_STRING": val = category.get_value_formatted_by_index(iattr, irow) line_list.append(val) line_list.append(spacing) self.__write("".join(line_list)) self.__write("\n")