2007-05-01 Don Allingham <don@gramps-project.org>

* src/ReportBase/_SimpleAccess.py: simplifed database access routines



svn: r8433
This commit is contained in:
Don Allingham 2007-05-02 04:05:41 +00:00
parent 37255a3b02
commit 9fd30ff3f9
8 changed files with 710 additions and 33 deletions

View File

@ -1,3 +1,6 @@
2007-05-01 Don Allingham <don@gramps-project.org>
* src/ReportBase/_SimpleAccess.py: simplifed database access routines
2007-04-30 Benny Malengier <bm@cage.ugent.be>
* src/Editors/_EditPlace.py:
* src/Editors/_EditSource.py:

4
TODO
View File

@ -5,12 +5,12 @@
will not be around forever. We need to adapt to the new GTK method.
* Add support for formatted notes. We have a start by ripping off code
from GPL code from grecipe-manager.
from GPL code from grecipe-manager. - DONE
* Allow for multiple notes. A tabbed interface would be really useful,
since there are no titles for notes. Not all objects would
necessarily need multiple notes. Determine which ones should and
shouldn't.
shouldn't. - DONE
* Split views

View File

@ -161,6 +161,7 @@ class GrampsBSDDB(GrampsDbBase,UpdateCallback):
def open_table(self,file_name,table_name,dbtype=db.DB_HASH):
dbmap = dbshelve.DBShelf(self.env)
dbmap.db.set_pagesize(16384)
print file_name
if self.readonly:
dbmap.open(file_name, table_name, dbtype, db.DB_RDONLY)
else:

View File

@ -48,7 +48,7 @@ from _MarkerType import MarkerType
# Localized constants
#
#-------------------------------------------------------------------------
_codeset = GrampsLocale.codeset
CODESET = GrampsLocale.codeset
#-------------------------------------------------------------------------
#
@ -110,7 +110,7 @@ class BasicPrimaryObject(BaseObject, PrivacyBase):
"""
if self.change:
return unicode(time.strftime('%x %X', time.localtime(self.change)),
_codeset)
CODESET)
else:
return u''
@ -189,21 +189,54 @@ class BasicPrimaryObject(BaseObject, PrivacyBase):
pass
def set_marker(self, marker):
"""
Sets the marker for the object.
@param marker: marker assigned to the object
@type marker: MarkerType
"""
self.marker.set(marker)
def get_marker(self):
"""
Returns the marker for the object. The exact type depends on the
derived class type.
@return: Returns the marker for the object.
@type marker: MarkerType
"""
return self.marker
def has_source_reference(self, handle):
"""
Indicates if the object has a source references. In the base class,
no such references exist. Derived classes should override this if they
provide source references.
"""
return False
def has_media_reference(self, handle):
"""
Indicates if the object has a media references. In the base class,
no such references exist. Derived classes should override this if they
provide media references.
"""
return False
def remove_source_references(self, handle_list):
"""
Removes the specified source references from the object. In the base class
no such references exist. Derived classes should override this if they
provide source references.
"""
pass
def remove_media_references(self, handle_list):
"""
Removes the specified media references from the object. In the base class
no such references exist. Derived classes should override this if they
provide media references.
"""
pass
def replace_source_references(self, old_handle, new_handle):

View File

@ -30,6 +30,9 @@ from gettext import gettext as _
__revision__ = "$Revision$"
class ChildRefType(GrampsType):
"""
Provides the different ChildRef types.
"""
NONE = 0
BIRTH = 1

View File

@ -0,0 +1,632 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Provides a simplified database access interface to the GRAMPS database.
"""
from types import NoneType
import RelLib
import DateHandler
import Utils
from BasicUtils import NameDisplay
from ReportBase import ReportUtils
class SimpleAccess:
"""
Provides a simplified database access system. This system has been designed to
ease the development of reports.
The user needs to take care when using this interface. Since it returns real
objects instead of database references, it can consume a significant amount
of memory if the user is not careful.
Example
=======
A typical system of usage would be::
sa = SimpleAccess(database)
print "Person : ", sa.name(person)
print "Gender : ", sa.gender(person)
print "Birth date : ", sa.birth_date(person)
print "Birth place : ", sa.birth_place(person)
print "Death date : ", sa.death_date(person)
print "Death place : ", sa.death_place(person)
print "Father : ", sa.name(sa.father(person))
print "Mother : ", sa.name(sa.mother(person))
print "Spouse : ", sa.name(sa.spouse(person))
print "Marriage Type : ", sa.marriage_type(person)
print "Marriage Date : ", sa.marriage_date(person)
print "Marriage Place: ", sa.marriage_place(person)
for child in sa.children(person):
print "Child : ", sa.name(child)
# Print out burial and baptism events
for event in sa.events( person , [ "Burial", "Baptism" ]):
print "Event : ", sa.event_type(event), sa.event_date(event),
print sa.event_place(event)
This would produce an output that looks like::
Person : Garner, Lewis Anderson
Gender : male
Birth date : 6/21/1855
Birth place : Great Falls, MT
Death date : 6/28/1911
Death place : Twin Falls, ID
Father : Garner, Robert W.
Mother : Zielinski, Phoebe Emily
Spouse : Martel, Luella Jacques
Marriage Type : Married
Marriage Date : 4/1/1875
Marriage Place: Paragould, AR
Child : Garner, Eugene Stanley
Child : Garner, Jesse V.
Child : Garner, Raymond E.
Child : Garner, Jennie S.
Child : Garner, Walter E.
Child : Garner, Daniel Webster
Child : Garner, Bertha P.
Child : Garner, Elizabeth
Event : Burial 7/1/1911 Twin Falls, ID
"""
def __init__(self, dbase):
"""
Initializes the SimpleAccess object with the database that will be used.
@param dbase: GRAMPS database object
@type dbase: GrampsDbBase
"""
self.dbase = dbase
def name(self, person):
"""
Returns the name of the person, or and empty string if the person is None
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns the name of the person based of the program preferences
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
return NameDisplay.displayer.display(person)
else:
return u''
def surname(self, person):
"""
Returns the name of the person, or and empty string if the person is None
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns the name of the person based of the program preferences
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
return person.get_primary_name().get_surname()
else:
return u''
def gid(self, obj):
"""
Returns the GRAMPS ID of the person or family
@param obj: Person or Family object
@type obj: L{RelLib.Person} or L{RelLib.Family}
@return: Returns the GRAMPS Id value of the person or family
@rtype: unicode
"""
assert(isinstance(obj, (RelLib.Person, RelLib.Family, NoneType)))
if obj:
return obj.get_gramps_id()
else:
return u''
def gender(self, person):
"""
Returns a string representing the gender of the person
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indentifying the person's gender
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
return Utils.gender[person.get_gender()]
return u''
def __parent(self, person, func):
"""
Returns a person associated as a parent of the person
@param person: Person object
@type person: L{RelLib.Person}
@param func: function used to extract the appropriate parent
@type func: function
@return: mother or father of the associated person
@rtype: L{RelLib.Person}
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
parent_handle_list = person.get_parent_family_handle_list()
if parent_handle_list:
family_id = parent_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
return self.__family_parent(family, func)
return None
def __family_parent(self, family, func):
"""
Returns a person associated as a parent of the family
@param family: Family object
@type family: L{RelLib.Family}
@param func: function used to extract the appropriate parent
@type func: function
@return: mother or father of the associated family
@rtype: L{RelLib.Family}
"""
assert(isinstance(family, (RelLib.Family, NoneType)))
if family:
handle = func(family)
if handle:
return self.dbase.get_person_from_handle(handle)
return None
def __event_date(self, person, func):
"""
Returns a string describing the date associated with the person
@param person: Person object
@type person: L{RelLib.Person}
@param func: function used to extract the associated date information
@type func: function
@return: Returns a string describing the date
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
ref = func(person)
if ref:
event_handle = ref.get_reference_handle()
if event_handle:
event = self.dbase.get_event_from_handle(event_handle)
date_obj = event.get_date_object()
if date_obj:
return DateHandler.displayer.display(date_obj)
return u''
def __event_place(self, person, func):
"""
Returns a string describing the place associated with the person
@param person: Person object
@type person: L{RelLib.Person}
@param func: function used to extract the associated place information
@type func: function
@return: Returns a string describing the place
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
ref = func(person)
if ref:
event_handle = ref.get_reference_handle()
if event_handle:
event = self.dbase.get_event_from_handle(event_handle)
place_handle = event.get_place_handle()
return ReportUtils.place_name(self.dbase, place_handle)
return u''
def spouse(self, person):
"""
Returns the primary spouse of the person
@param person: Person object
@type person: L{RelLib.Person}
@return: The spouse identified as the person's primary spouse
@rtype: L{RelLib.Person}
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
family_handle_list = person.get_family_handle_list()
if family_handle_list:
family_id = family_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
if family.get_father_handle() == person.get_handle():
person_handle = family.get_mother_handle()
else:
person_handle = family.get_father_handle()
if person_handle:
return self.dbase.get_person_from_handle(person_handle)
return None
def marriage_type(self, person):
"""
Returns a string describing the relationship between the person and
his/per primary spouse.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string describing the relationship between the person and
his/per primary spouse.
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
family_handle_list = person.get_family_handle_list()
if family_handle_list:
family_id = family_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
if family:
return str(family.get_relationship())
return u''
def marriage_place(self, person):
"""
Returns a string describing the place where the person and his/her spouse
where married.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string describing the place where the person and his/her spouse
where married.
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
family_handle_list = person.get_family_handle_list()
if family_handle_list:
family_id = family_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
if family:
reflist = family.get_event_ref_list()
if reflist:
ref = reflist[0].ref
event = self.dbase.get_event_from_handle(ref)
place_handle = event.get_place_handle()
return ReportUtils.place_name(self.dbase, place_handle)
return u''
def marriage_date(self, person):
"""
Returns a string indicating the date when the person and his/her spouse
where married.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indicicating the date when the person and his/her spouse
where married.
@rtype: unicode
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
family_handle_list = person.get_family_handle_list()
if family_handle_list:
family_id = family_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
if family:
reflist = family.get_event_ref_list()
if reflist:
ref = reflist[0].ref
event = self.dbase.get_event_from_handle(ref)
date_obj = event.get_date_object()
if date_obj:
return DateHandler.displayer.display(date_obj)
return u''
def children(self, obj):
"""
Returns a list of the children as the children of the primary spouse.
@param obj: Person or Family object
@type obj: L{RelLib.Person} or L{RelLib.Family}
@return: Returns a list of L{RelLib.Person} objects representing the children
@rtype: list
"""
assert(isinstance(obj, (RelLib.Person, RelLib.Family, NoneType)))
if isinstance(obj, RelLib.Person):
family_handle_list = obj.get_family_handle_list()
if family_handle_list:
family_id = family_handle_list[0]
family = self.dbase.get_family_from_handle(family_id)
return [ self.dbase.get_person_from_handle(hndl.ref)
for hndl in family.get_child_ref_list() ]
elif isinstance(obj, RelLib.Family):
return [ self.dbase.get_person_from_handle(hndl.ref)
for hndl in obj.get_child_ref_list() ]
return []
def father(self, obj):
"""
Returns the primary father of the person or the father of the associated
family.
@param obj: Person or Family object
@type obj: L{RelLib.Person} or L{RelLib.Family}
@return: The father in the person's primary family or the father of the
family
@rtype: L{RelLib.Person}
"""
if isinstance(obj, RelLib.Person):
return self.__parent(obj, RelLib.Family.get_father_handle)
elif isinstance(obj, RelLib.Family):
return self.__family_parent(obj, RelLib.Family.get_father_handle)
else:
return None
def mother(self, obj):
"""
Returns the primary mother of the person or the mother of the associated
family.
@param obj: Person object
@type obj: L{RelLib.Person} or L{RelLib.Family}
@return: The mother in the person's primary family or the mother of the
family
@rtype: L{RelLib.Person}
"""
if isinstance(obj, RelLib.Person):
return self.__parent(obj, RelLib.Family.get_mother_handle)
elif isinstance(obj, RelLib.Family):
return self.__family_parent(obj, RelLib.Family.get_mother_handle)
else:
return None
def birth_date(self, person):
"""
Returns a string indicating the date when the person's birth.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indicating the date when the person's birth.
@rtype: unicode
"""
return self.__event_date(person, RelLib.Person.get_birth_ref)
def birth_place(self, person):
"""
Returns a string indicating the place of the person's birth.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indicating the place of the person's birth.
@rtype: unicode
"""
return self.__event_place(person, RelLib.Person.get_birth_ref)
def death_date(self, person):
"""
Returns a string indicating the date when the person's death.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indicating the date when the person's death.
@rtype: unicode
"""
return self.__event_date(person, RelLib.Person.get_death_ref)
def death_place(self, person):
"""
Returns a string indicating the place of the person's death.
@param person: Person object
@type person: L{RelLib.Person}
@return: Returns a string indicating the place of the person's death.
@rtype: unicode
"""
return self.__event_place(person, RelLib.Person.get_death_ref)
def event_place(self, event):
"""
Returns a string indicating the place of the event
@param event: Event object
@type event: L{RelLib.Event}
@return: Returns a string indicating the place of the event
@rtype: unicode
"""
assert(isinstance(event, (RelLib.Event, NoneType)))
if event:
place_handle = event.get_place_handle()
return ReportUtils.place_name(self.dbase, place_handle)
else:
return u''
def event_date(self, event):
"""
Returns a string indicating the date of the event
@param event: Event object
@type event: L{RelLib.Event}
@return: Returns a string indicating the date of the event
@rtype: unicode
"""
assert(isinstance(event, (RelLib.Event, NoneType)))
date_obj = event.get_date_object()
if date_obj:
return DateHandler.displayer.display(date_obj)
else:
return u''
def event_type(self, event):
"""
Returns a string indicating the type of the event
@param event: Event object
@type event: L{RelLib.Event}
@return: Returns a string indicating the type of the event
@rtype: unicode
"""
assert(isinstance(event, (RelLib.Event, NoneType)))
if event:
return str(event.get_type())
else:
return u''
def events(self, obj, restrict=None):
"""
Returns a list of events associated with the object. This object
can be either a L{RelLib.Person} or L{RelLib.Family}.
@param obj: Person or Family
@type obj: L{RelLib.Person} or L{RelLib.Family}
@param restrict: Optional list of strings that will limit the types
of events to those of the specfied types.
@type restrict: list
@return: list of events assocated with the object
@rtype: list
"""
assert(isinstance(obj, (RelLib.Person, RelLib.Family, NoneType)))
assert(type(restrict) == type([]) or restrict == None)
if obj:
event_handles = [ ref.ref for ref in obj.get_event_ref_list() ]
events = [ self.dbase.get_event_from_handle(h)
for h in event_handles ]
if restrict:
restrict = [ r.lower() for r in restrict ]
events = [ event for event in events
if str(event.get_type()).lower() in restrict ]
return events
else:
return []
def parent_in(self, person):
"""
Returns a list of families in which the person is listed as a parent.
@param person: Person object
@type person: L{RelLib.Person}
@return: list of L{RelLib.Family} objects in which the person is listed
as a parent.
@rtype: list
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
return [ self.dbase.get_family_from_handle(handle)
for handle in person.get_family_handle_list() ]
return []
def child_in(self, person):
"""
Returns a list of families in which the person is listed as a child.
@param person: Person object
@type person: L{RelLib.Person}
@return: list of L{RelLib.Family} objects in which the person is listed
as a child.
@rtype: list
"""
assert(isinstance(person, (RelLib.Person, NoneType)))
if person:
return [ self.dbase.get_family_from_handle(handle)
for handle in person.get_parent_family_handle_list() ]
return []
def all_people(self):
"""
Returns a all the people in the database, one at a time as an iterator.
The user can treat this just like a list. For example::
for person in sa.all_people():
sa.print(person)
@return: list of people in the database
@rtype: list
"""
slist = []
cursor = self.dbase.get_person_cursor()
data = cursor.first()
while data:
slist.append((data[1][3][3], data[0]))
data = cursor.next()
cursor.close()
slist.sort()
for info in slist:
person = self.dbase.get_person_from_handle(info[1])
yield person
# if __name__ == "__main__":
# from GrampsDb import gramps_db_factory
# import sys
# import const
# db_class = gramps_db_factory(const.app_gramps_xml)
# database = db_class()
# database.load(sys.argv[1], lambda x: None, mode="w")
# person = database.get_default_person()
# sa = SimpleAccess(database)
# print "Person : ", sa.name(person)
# print "Gender : ", sa.gender(person)
# print "Birth date : ", sa.birth_date(person)
# print "Birth place : ", sa.birth_place(person)
# print "Death date : ", sa.death_date(person)
# print "Death place : ", sa.death_place(person)
# print "Father : ", sa.name(sa.father(person))
# print "Mother : ", sa.name(sa.mother(person))
# print "Spouse : ", sa.name(sa.spouse(person))
# print "Marriage Type : ", sa.marriage_type(person)
# print "Marriage Date : ", sa.marriage_date(person)
# print "Marriage Place: ", sa.marriage_place(person)
# for child in sa.children(person):
# print "Child : ", sa.name(child)
# for event in sa.events( person , [ "Burial" ]):
# print "Event : ", sa.event_type(event), \
# sa.event_date(event), sa.event_place(event)
# # for person in sa.all_people():
# # print sa.name(person)
# print "************************************************"
# for family in sa.parent_in(person):
# print "Father : ", sa.name(sa.father(family))
# print "Mother : ", sa.name(sa.mother(family))
# print "************************************************"
# for family in sa.child_in(person):
# print "Father : ", sa.name(sa.father(family))
# print "Mother : ", sa.name(sa.mother(family))

View File

@ -72,7 +72,7 @@ import PageView
import Navigation
import TipOfDay
import Bookmarks
import RecentFiles
#import RecentFiles
from BasicUtils import NameDisplay
import GrampsWidgets
import UndoHistory
@ -81,6 +81,8 @@ import GrampsDisplay
from GrampsDb import ProgressMonitor
import ProgressDialog
from bsddb.db import DBRunRecoveryError, DBAccessError, \
DBPageNotFoundError, DBInvalidArgError
def show_url(dialog, link, user_data):
"""
@ -250,8 +252,8 @@ class ViewManager:
vbox.pack_start(self.menubar, False)
vbox.pack_start(self.toolbar, False)
vbox.add(hbox)
self.progress_monitor = ProgressMonitor(ProgressDialog.GtkProgressDialog,
("",self.window))
self.progress_monitor = ProgressMonitor(
ProgressDialog.GtkProgressDialog, ("",self.window))
self.progress = gtk.ProgressBar()
self.progress.set_size_request(100, -1)
self.progress.hide()
@ -273,7 +275,8 @@ class ViewManager:
self.state.connect('database-changed', self.uistate.db_changed)
toolbar = self.uimanager.get_widget('/ToolBar')
self.filter_menu = self.uimanager.get_widget('/MenuBar/ViewMenu/Filter/')
self.filter_menu = self.uimanager.get_widget(
'/MenuBar/ViewMenu/Filter/')
openbtn = gtk.MenuToolButton('gramps-db')
openbtn.connect('clicked', self.open_activate)
@ -349,7 +352,8 @@ class ViewManager:
('PluginStatus', None,_('_Plugin status'), None, None,
self.plugin_status),
('FAQ', None, _('_FAQ'), None, None, self.faq_activate),
('KeyBindings', None, _('_Key Bindings'), None, None, self.key_bindings),
('KeyBindings', None, _('_Key Bindings'), None, None,
self.key_bindings),
('UserManual', gtk.STOCK_HELP, _('_User Manual'), 'F1', None,
self.manual_activate),
('TipOfDay', None, _('Tip of the day'), None, None,
@ -532,7 +536,7 @@ class ViewManager:
self.uistate.set_busy_cursor(1)
self.uistate.progress.show()
self.uistate.push_message(self.state, _("Autobackup..."))
writer = GrampsDbUtils.Backup.export(self.state.db)
GrampsDbUtils.Backup.export(self.state.db)
self.uistate.set_busy_cursor(0)
self.uistate.progress.hide()
@ -669,7 +673,7 @@ class ViewManager:
about.set_license(ifile.read().replace('\x0c', ''))
ifile.close()
except:
pass
about.set_license("License file is missing")
about.set_comments(_(const.comments))
about.set_website_label(_('GRAMPS Homepage'))
about.set_website(const.url_homepage)
@ -984,7 +988,7 @@ class ViewManager:
_("Could not open file: %s") % filename,
str(msg[1]))
except Exception:
log.error("Failed to open database.", exc_info=True)
LOG.error("Failed to open database.", exc_info=True)
return True
@ -1003,9 +1007,9 @@ class ViewManager:
# Attempt to figure out the database title
path = os.path.join(filename, "name.txt")
try:
f = open(path)
title = f.readline().strip()
f.close()
ifile = open(path)
title = ifile.readline().strip()
ifile.close()
except:
title = filename
@ -1024,7 +1028,7 @@ class ViewManager:
self.state.db.undo_history_callback = self.undo_history_update
self.undo_history_close()
self.window.window.set_cursor(None)
self.uistate.window.window.set_cursor(None)
def post_load_newdb(self, filename, filetype, title=None):

View File

@ -104,7 +104,6 @@ class PreviewCanvas(gtk.DrawingArea):
def expose(self, widget, event):
"""Ask the print operation to actually draw the page."""
print "expose"
self.window.clear()
self._preview_operation.render_page(self._page_no)
@ -215,6 +214,8 @@ def paperstyle_to_pagesetup(paper_style):
else:
page_setup.set_orientation(gtk.PAGE_ORIENTATION_LANDSCAPE)
gpaper_size = paper_style.get_size()
# This causes my gtk to seg fault.
#paper_size = gtk.PaperSize(paper_style.get_name())
#if paper_size.is_custom():
@ -227,8 +228,8 @@ def paperstyle_to_pagesetup(paper_style):
# GtkWarning: gtk_paper_size_set_size: assertion `size->is_custom' failed
# But I don't know how to tell it that it is custom without it segfaulting.
paper_size = gtk.PaperSize()
paper_size.set_size(paper_style.get_width()*10,
paper_style.get_height()*10,
paper_size.set_size(gpaper_size.get_width()*10,
gpaper_size.get_height()*10,
gtk.UNIT_MM)
page_setup.set_paper_size(paper_size)