Package XPyTools :: Package codetpl :: Module codetpl
[hide private]
[frames] | no frames]

Source Code for Module XPyTools.codetpl.codetpl

  1  #!/usr/bin/env python
 
  2  # -*- coding: utf-8 -*-
 
  3  #--------------------------------------------------------------------
 
  4  # Author: Mazhugin Aleksey
 
  5  # Created: 2007/09/25
 
  6  # ID: $Id: XPyTools.codetpl.codetpl-pysrc.html 24 2008-12-01 17:51:12Z alex $
 
  7  # URL: $URL: file:///myfiles/svn_/XPyLIB/trunc/doc/html/XPyTools.codetpl.codetpl-pysrc.html $
 
  8  # Copyright: Copyright (c) 2007, Mazhugin Aleksey
 
  9  # License: BSD
 
 10  #--------------------------------------------------------------------
 
 11  
 
 12  """
 
 13  Main code template module.
 
 14  
 
 15  Overview.
 
 16  =========
 
 17      
 
 18      Provide core functionality for code templates.
 
 19      
 
 20      Tunning of this module may be prformed by using configuration files.
 
 21      Default file is "I{codetpl_default.cfg}" that must not be changed.
 
 22      User preferences may be added to custom configuration files named
 
 23      "I{codetpl.cfg}" . Search for custom configuration files in all
 
 24      templates folder and combined and override settings from las files.
 
 25      
 
 26      Module have next objects:
 
 27          - Exceptions: L{codetplError}, L{codetplArgumentError},
 
 28              L{codetplTemplateException}.
 
 29          - Main class L{CodeTemplateMngr} that provide core manager for templates.
 
 30          - Variable L{ANY} value of which is equivalent any other value in
 
 31              metainformation of templates.
 
 32  
 
 33  X{CodeTemplateMngr overview}.
 
 34  =============================
 
 35      
 
 36      Use L{CodeTemplateMngr.HasType} to test type for exists.
 
 37      Use L{CodeTemplateMngr.GetTemplates} to get available templates list.
 
 38      Use L{CodeTemplateMngr.MetaNames}, L{CodeTemplateMngr.GetMetaInfo},
 
 39      L{CodeTemplateMngr.GetMetaAllValues} to get metainformation about
 
 40      templates.
 
 41      Use L{CodeTemplateMngr.Types} to get available types of templates.
 
 42      Use L{CodeTemplateMngr.GetConfig} to get preferences from
 
 43      configuration files.
 
 44      Use L{CodeTemplateMngr.ParseTemplate} to parse templates.
 
 45      
 
 46      You can reload module for changest in files make effect by calling
 
 47      L{CodeTemplateMngr.Reload}.
 
 48  
 
 49  X{Configuration file (CodeTemplateMngr)}.
 
 50  =========================================
 
 51      
 
 52      The user configuration file example (it's get from codetpl_default)::
 
 53      
 
 54          #!/usr/bin/env python
 
 55          # -*- coding: utf-8 -*-
 
 56          #--------------------------------------------------------------------
 
 57          # Author: Mazhugin Aleksey
 
 58          # Created: 2007/10/24
 
 59          # ID: $Id: XPyTools.codetpl.codetpl-pysrc.html 24 2008-12-01 17:51:12Z alex $
 
 60          # URL: $URL: file:///myfiles/svn_/XPyLIB/trunc/doc/html/XPyTools.codetpl.codetpl-pysrc.html $
 
 61          # Copyright: Copyright (c) 2007, Mazhugin Aleksey
 
 62          # License: BSD
 
 63          #--------------------------------------------------------------------
 
 64          
 
 65          # Default settings for Code templates.
 
 66          #
 
 67          # This config file for users folder. 
 
 68          # You may copy and rename it to you home
 
 69          # "~/.xpylib/xpytools/codetpl/templates/codetpl.cfg"
 
 70          # and edit configuration.
 
 71          
 
 72          [Prefs]
 
 73          
 
 74          # If true then will be loaded global templates from
 
 75          # "XPyLIB/XPyTools/codetpl/templates/".
 
 76          # If False when will be used only user templates.
 
 77          UseGlobalTemplates = yes
 
 78          
 
 79          #If true then reload templates files every tyme, else only
 
 80          # at startup. Also with templates each time reload configuration
 
 81          # file.
 
 82          ReloadTemplates = yes
 
 83          
 
 84          # Templates types.
 
 85          # Preferences for each type see in [type_???] section.
 
 86          # If type is not included then it will be not used.
 
 87          types = act, new, wzd, kwd, tpl, wtp
 
 88          
 
 89          # Prefix for types sections.
 
 90          # Types sectins will be search into typesprefix??? where ???-type.
 
 91          typesprefix = type_
 
 92          
 
 93          # Meta information fields names.
 
 94          MetaNames = category, language, author
 
 95          
 
 96          # Any value equivalent
 
 97          ANY = any
 
 98          
 
 99          #If not empty then add to Tools menu with it name.
 
100          # TODO: Not releazed yet, add.
 
101          ToolMenuName = Code Template
 
102          
 
103          [Template_paths]
 
104          
 
105          ################################################################################
 
106          #Template paths.
 
107          ################################################################################
 
108          
 
109          # Default path - same dir as config file.
 
110          path1 = .
 
111          
 
112          # Additional paths.
 
113          #path2 = 
 
114          #path3 = 
 
115          
 
116          
 
117          
 
118          ################################################################################
 
119          # Types settings
 
120          ################################################################################
 
121          #
 
122          # Name - Full name for template.
 
123          #
 
124          # Desc - Description for given type.
 
125          #
 
126          # HotKey - Hot key for call teplates from editor.
 
127          #
 
128          # MenuName - If exist and not empty then register in to menu Edit->... .
 
129          #
 
130          # Interface - Interface of template type. May be:
 
131          #   - 'gui' - GUI interface (used by default).
 
132          #   - 'list' - Standard editor list popup.
 
133          #
 
134          
 
135          [type_act]
 
136          Name = Action
 
137          Desc = Action for code manipulation
 
138          HotKey = Alt+A
 
139          Interface = list
 
140          MenuName = Code Template Action
 
141          
 
142          [type_kwd]
 
143          Name = Keywords
 
144          Desc = Any keywords
 
145          HotKey = Alt+K
 
146          Interface = list
 
147          MenuName = Code Template Keyword
 
148          
 
149          [type_tpl]
 
150          Name = Code
 
151          Desc = Code templates
 
152          HotKey = Alt+T
 
153          Interface = list
 
154          MenuName = Code Template Template
 
155          
 
156          [type_wzd]
 
157          Name = Wizard
 
158          Desc = Wizard for code creation.
 
159          HotKey = 
 
160          Interface = gui
 
161          MenuName = Code Template Wizard
 
162          
 
163          [type_new]
 
164          Name = New
 
165          Desc = Templates for new files
 
166          HotKey = Alt+Q
 
167          Interface = gui
 
168          MenuName = Code Tpl New
 
169          
 
170          [type_wtp]
 
171          Name = XTemplate
 
172          Desc = Extended code templates.
 
173          HotKey =
 
174          Interface = gui
 
175          MenuName = Code Tpl Tpls wizard
 
176  
 
177  @var ANY: Value that equivalent any other value (used in metainformation).
 
178  @type ANY: str
 
179  
 
180  """ 
181  
 
182  import sys 
183  import os 
184  import imp 
185  import inspect 
186  import glob 
187  import re 
188  import ConfigParser 
189  import XPyLIB 
190  ##import XPyLIB.dbg as dbg ##@
 
191      
 
192  # var: Value that equivalent any other value (used in metainformation).
 
193  # type: str
 
194  ANY = 'any' 
195  
 
196 -class codetplError(Exception):
197 """ 198 Code templates common exception. 199 """ 200 pass
201
202 -class codetplArgumentError(codetplError):
203 """ 204 Code templates argument exception. 205 """ 206 pass
207
208 -class codetplTemplateException(codetplError):
209 """ 210 Exception then executing template function. 211 212 Argument Err is Exception object. 213 """ 214 pass
215
216 -class CodeTemplateMngr(object):
217 """ 218 Manager of code templates. 219 220 Provide all functionalities with templates. 221 """ 222
223 - def __get_Errors(self):
224 return self.__errs[:]
225
226 - def __del_Errors(self):
227 self.__errs=[]
228 229 #: @ivar: List of errors string (copy, not original). 230 #: @type: list 231 Errors = property(__get_Errors, None, __del_Errors) 232 233 @property
234 - def Types(self):
235 """ 236 List of available templates types (copy, not original). 237 Type - list. 238 """ 239 return self.__types[:]
240 241 @property
242 - def MetaNames(self):
243 """ 244 List of available metanames (copy, not original). 245 Type - list. 246 """ 247 return self.__metanames[:]
248 249 @property
250 - def SourceFile(self):
251 """ 252 Source file which editing in the editor. 253 Type - str = C{''} 254 """ 255 return self.__srcfile
256
257 - def __init__(self, spath = [], usedefault = True):
258 """ 259 Initialize class. 260 261 @param spath: List of absolute paths to templates folders. If empty string 262 (or C{False}) then set default path == "... /codetpl/templates/" 263 @type spath: list[string] = C{[]} 264 @param usedefault: If true then load global and user config files and 265 if allow use global templates. Otherwise use only path from L{spath}. 266 @type usedefault: bool = True 267 @raise codetplArgumentError: Template path does not exist. May raise 268 for default path or user specified. 269 @warning: Into initialization folder must be placed configuration 270 file B{C{codetpl.cfg}} else wil be used default values (see 271 module description). 272 """ 273 274 #: @ivar: Edited source file, from which called templates. 275 #: @type: string = C{''} 276 self.__srcfile='' 277 278 #: @ivar: C{SafeConfigParser} instance. 279 #: @type: SafeConfigParser 280 self.__config=None 281 282 #: @ivar: Loaded module's names. 283 #: @type: list = C{[]} 284 self.__mdls=[] 285 286 #: @ivar: Keywords functions readed from files: 287 #: {"FullMame=???_*",Code_object}. 288 #: @type: dict = C{{}} 289 self.__kwds={} 290 291 #: @ivar: Other templates. 292 #: {"FullMame=???_*" : func_object} 293 #: @type: dict = C{{}} 294 self.__tpls={} 295 296 #: @ivar: Templates meta (all for keywords and other). 297 #: { "FullMame=???_*" : {"metaname" : "metavalue"} } 298 #: @type: dict = C{{}} 299 self.__tplsmeta={} 300 301 #: @ivar: Errors list. You must clear it's self. 302 #: Auto clear then L{Reload() <Reload>} calls. 303 #: @type: list = C{[]} 304 self.__errs=[] 305 306 #: @ivar: Available types for templates. 307 #: @type: list = C{[]} 308 self.__types=[] 309 310 if type(spath) == str: 311 spath=[spath] 312 #: @ivar: List paths to templates. 313 #: @type: list[str] 314 #: paths to folders with templates. 315 self.__path = spath 316 317 #: @ivar: If true then load global and user config files and 318 #: if allow use global templates. Otherwise use only path from L{spath}. 319 #: @type: bool = True 320 self.__usedefault = usedefault 321 322 #: @ivar: Names for available fields of metainformation (must present). 323 #: @type: list 324 self.__metanames=['category', 'language'] 325 326 #: @ivar: Regular exspression for metainformation fields (must present). 327 #: @type: list 328 self.__metare=[ re.compile(r'^#\s*' + n + r'\s*=\s*(?P<' + \ 329 n + r'>.*)$', re.M) for n in self.__metanames ] 330 331 self.Reload()
332
333 - def GetConfig(self, section, option=None, default=''):
334 """ 335 Return preferences from configuration files. 336 337 You may get option value or section items: 338 - Option. 339 If option not exist then return default value. 340 - Section. 341 For get section items you must leave I{option} parameter 342 empty or set to C{None}. 343 If no such section then return empty list []. 344 345 @param section: Section name. 346 @type section: str 347 @param option: Option name. 348 @type option: str=C{''} 349 @param default: Default value. 350 @type default: str=C{''} 351 @return: Configuration value or list of items for section. 352 @rtype: str or list[(name, value)] 353 """ 354 if option == None: 355 return self.__config.has_section(section) and \ 356 self.__config.items(section) or [] 357 else: 358 return self.__config.has_section(section) and \ 359 self.__config.has_option(section, option) and \ 360 self.__config.get(section, option) or default
361
362 - def Reload(self):
363 """ 364 Re/Load template and config modules. 365 366 Clear previous loaded modules and reload all noe finded. 367 All loaded template modules into __mdls, naming is as "_codetpl_???_*". 368 Walk throw all loaded modules and fill __kwds and __tpls dictionaries. 369 370 @return: None. 371 @rtype: None 372 """ 373 ##dbg.fwriteln('codetpl.Reload()') ##@ 374 # Clear line cache from inspect module. 375 inspect.linecache.clearcache() 376 377 # Clear all. 378 self.__kwds.clear() 379 self.__tpls.clear() 380 self.__errs=[] 381 self.__types=[] 382 self.__tplsmeta.clear() 383 384 self.__config = ConfigParser.SafeConfigParser() 385 386 if self.__usedefault: 387 # Read default config. 388 defcfgpath = os.path.join( os.path.dirname(__file__), \ 389 'templates', 'codetpl_default.cfg') 390 if os.path.exists(defcfgpath): 391 # Read default. 392 try: 393 ## dbg.writeln('\t load defcfg==', defcfgpath) ##@ 394 fp=open(defcfgpath) 395 self.__config.readfp(fp) 396 except: 397 ## dbg.writeln('\t load defcfg==failed', defcfgpath) ##@ 398 pass # Be quit. 399 finally: 400 if fp: 401 fp.close() 402 403 # Read user config. 404 defcfgpath = XPyLIB.dir_get('xpytools/codetpl/templates', True, True) 405 defcfgpath = os.path.join( defcfgpath , 'codetpl.cfg') 406 if os.path.exists(defcfgpath): 407 # Read user config. 408 try: 409 ## dbg.writeln('\t load defcfg==', defcfgpath) ##@ 410 fp=open(defcfgpath) 411 self.__config.readfp(fp) 412 except: 413 ## dbg.writeln('\t load defcfg==failed', defcfgpath) ##@ 414 pass # Be quit. 415 finally: 416 if fp: 417 fp.close() 418 419 if self.GetConfig('Prefs','UseGlobalTemplates','yes') == 'yes': 420 self.__path.append( os.path.join( os.path.dirname(__file__), 'templates') ) 421 ##if self.__usedefault 422 423 # Load configs from paths. 424 defcfgpath = [os.path.join( p, 'codetpl.cfg') 425 for p in self.__path] 426 ## dbg.writeln('\t load ini cfg==', defcfgpath) ##@ 427 self.__config.read(defcfgpath) 428 429 # Get config available types. 430 availtypes=[n.strip() for n in self.GetConfig('Prefs','types','').split(',')] 431 global ANY 432 ANY=self.GetConfig('Prefs','ANY','any') 433 # Get config metanames. 434 mns=[n.strip() for n in self.GetConfig('Prefs','MetaNames','').split(',')] 435 for mn in mns: 436 if mn not in self.__metanames: 437 self.__metanames.append(mn) 438 self.__metare.append( re.compile(r'^#\s*' + mn + r'\s*=\s*(?P<' + \ 439 mn + r'>.*)$', re.M) ) 440 ##end for mn 441 442 ## dbg.writeln('\n\tavailabletypes==',availtypes) ##@ 443 444 ##dbg.fwriteln('codetpl.Reload() delete modules:', self.__mdls) ##@ 445 for f in self.__mdls: 446 try: 447 ##dbg.fwriteln('codetpl.Reload() try pop: ', str(f)) ##@ 448 m=sys.modules.pop('_codetpl_' + f, 1) ## 0 - for quet work if no module. 449 except Exception, e: 450 ##dbg.fwriteln('codetpl.Reload() except pop: ', str(f)) ##@ 451 pass 452 del m 453 ##dbg.fwriteln('codetpl.Reload() delete result:', ('_codetpl_' + f) not in sys.modules) ##@ 454 455 ## dbg.writeln([n for n in sys.modules.keys() if n.startswith('_')]) ##@ 456 self.__mdls=[] 457 458 # Loop folders 459 cfgpath=[v for k,v in self.GetConfig('Template_paths')] 460 ## dbg.writeln('\t load folders==', cfgpath) ##@ 461 ## dbg.writeln('\t folders paths==', self.__path + cfgpath) ##@ 462 for folder in self.__path + cfgpath: 463 ## dbg.writeln('\t *** folder==', folder) ##@ 464 if not os.path.exists(folder): 465 ## dbg.writeln('\t *** *** not exists', folder) ##@ 466 continue 467 # Loop for files into templates directory 468 ## dbg.writeln( 'glob=', os.path.join(folder,'???_*.py') ) ##@ 469 for f in glob.iglob(os.path.join(folder,'???_*.py')): 470 ## dbg.writeln('\t *** f==', f) ##@ 471 if not os.path.isdir(f): 472 # Create and add module name to list, load module. 473 # Save all names into lowercase. 474 n=os.path.splitext(os.path.basename(f))[0].lower() 475 pref=n[0:3] ## Template type. 476 # Load only types available by config. 477 # dbg.writeln('\n\tpref===',pref, ' n=', n) ##@ 478 if pref in availtypes: 479 try: 480 ## dbg.writeln( 'try load=', '_codetpl_' + n,'==', f ) ##@ 481 module = imp.load_source('_codetpl_' + n, f) 482 except Exception, error: 483 # Log error and quet pass. 484 ## dbg.writeln( ' try except' ) ##@ 485 self.__errs.append(str(error) + \ 486 '. (' + str(error.__class__) + ').') 487 else: 488 #If all OK'ey then continue. 489 ## dbg.writeln( ' try else' ) ##@ 490 ## You may uncomment this for prevent loading modules with equals names. 491 ## if n in self.__mdls: 492 ## # Except loadind twice modules with like names. 493 ## continue 494 self.__mdls.append(n) 495 # Import templates. 496 prefu=pref + '_' 497 for name, val in inspect.getmembers(module, \ 498 lambda m: inspect.isfunction(m) and \ 499 m.__name__.lower().startswith(prefu) ): 500 # Add function. 501 name=name.lower() 502 npref=name[0:3] 503 # Get metainformation. 504 ##vcmnts=str(inspect.getcomments(val)) 505 vcmnts=unicode(inspect.getcomments(val),errors='replace') #:PATCH: Unicode. 506 # Documentation string as description. 507 ##vdoc=str(inspect.getdoc(val)) 508 vdoc=unicode(inspect.getdoc(val),errors='replace') #:PATCH: Unicode. 509 if npref not in self.__types: 510 # Add types if new 511 self.__types.append(npref) 512 # Add meta info (desc==docstring,{metaname:metavalue}). 513 md=[] 514 for i in range(len(self.__metanames)): 515 n=self.__metanames[i] 516 ## dbg.writeln('\n\t\t Search metanames==',n) ##@ 517 m=self.__metare[i].search(vcmnts) 518 if m: 519 ## dbg.writeln('\n\t\t append metanames==',n, ' ** ', str(m.group(n)).strip()) ##@ 520 md.append( (n, str(m.group(n)).strip() or '') ) 521 ##end for n 522 self.__tplsmeta[name]=( vdoc, dict(md) ) 523 ## dbg.writeln('\n\t\t ADD META(',name,'==',( vdoc, dict(md) )) ##@ 524 if npref=='kwd': 525 # Add to keywords without type prefix. 526 self.__kwds[name[4:]]=val 527 else: 528 # Add to templates. 529 self.__tpls[name]=val
530 ##end if 531 ##end for 532 ##end try 533 ##end if 534 ##end for glob 535 ##end for folder 536
537 - def GetTemplates(self, type_, filter={}, retIfAbsent=False):
538 """ 539 Get list of available templates given type. 540 541 C{type} must be one from L{C{Types()}<Types>}. 542 If no such type then raise L{codetplArgumentError}. 543 544 C{type} are case insensetive (converts to lower). 545 546 Filter contains dictionary {name:listofvalues} where listofvalues 547 may be tuple, list or other iterable or str (converted to single tuple). 548 Filter do only from given metanames other is always done. 549 550 @param type_: Type of templates. 551 @type type_: str 552 @param filter: Filter from metainformation fields. 553 @type filter: dict=C{empty} 554 @param retIfAbsent: If metanames from filter absent in templates then 555 if C{True} return this template, if C{False} then skip. 556 @type retIfAbsent: boolean=C{False} 557 @return: List of templates name for given C{type}. 558 @rtype: list 559 @raise codetplArgumentError: If no such type of template. 560 """ 561 type_=type_.lower() 562 if not self.HasType(type_): 563 ##raise codetplArgumentError, 'Unknown template type:' + type_ +'.' 564 # Templates not found, write to stderr. 565 if type_ == '': 566 em = 'CodeTemplates: Templates not found.' 567 else: 568 em = 'CodeTemplates: Unknown template type: "' + type_ +'".' 569 sys.stderr.write(em) 570 # Return empty list 571 return [] 572 pref = type_ + '_' 573 if type_=='kwd': 574 tpls = self.__kwds.keys() 575 else: 576 # From names escaped "???_". 577 tpls = [name[4:] for name in self.__tpls.keys() 578 if name.startswith(pref)] 579 # Filter templates. 580 ret=[] 581 for n in tpls: 582 if filter: 583 # Convert to secuense. 584 for k,v in filter.items(): 585 if type(v) == str: 586 v=(v,) 587 if self.__tplsmeta[pref+n][1].has_key(k): 588 # Test key values. 589 vv=self.__tplsmeta[pref+n][1][k] 590 if (ANY in v) or (vv in v) or (vv==ANY): 591 # Append if value right. 592 ret.append(n) 593 else: 594 # No such key, try absent. 595 if retIfAbsent: 596 ret.append(n) 597 ##end if 598 ##end for k,v 599 else: 600 ret.append(n) 601 ##end if filter 602 ##end for n 603 604 ## dbg.writeln('\n TPLS==', tpls, '\n RET==',ret) ##@ 605 606 return ret
607
608 - def GetMetaInfo(self, type_, name):
609 """ 610 Get metainformation for requested template. 611 612 If C{type} or C{name} is absant then return C{I{ ('',{}) }} 613 614 @warning: Returned value is not copy, it saved object. If you 615 change it you change metainformation. 616 617 @param type_: Template type. 618 @type type_: str 619 @param name: Template name. 620 @type str 621 @return: Tuple of C{str} and C{dict} 622 ('docstr', {'metaname' : 'metavalue'}) 623 @rtype: tuple 624 """ 625 type_=type_.lower() 626 name=name.lower() 627 n = type_ + '_' + name 628 ## dbg.writeln('\n\t**** GETMETA==',type_+' ', name+' ', n+' ', self.__tplsmeta[n]) ##@ 629 return ( (type_ in self.__types) and self.__tplsmeta.has_key(n) \ 630 and self.__tplsmeta[n] ) or ('',{})
631
632 - def GetMetaAllValues(self, type_, metaname):
633 """Get list of all values find in given C{type} for given C{metaname}. 634 635 @param type_: Template type. 636 @type type_: str 637 @param metaname: Metaname. 638 @type str 639 @return: List of all values find in given C{type} for given C{metaname}. 640 @rtype: list 641 """ 642 pref=type_.lower() + '_' 643 metaname=metaname.lower() 644 ret=[] 645 for k,v in self.__tplsmeta.iteritems(): 646 if v[1].has_key(metaname): 647 vv=v[1][metaname] 648 if ret.count(vv)==0: 649 ret.append(vv) 650 return ret
651
652 - def ParseTemplate(self, type, name, fields, srcfile='', params={}):
653 """ 654 Parse template used given fields or return preview. 655 656 C{type} and C{name} are case insensetive (converts to lower). 657 658 If you get empty L{fields} then for all finded keywords will be 659 assigned it's name. It's used for preview template. For real parse 660 you may set into fields neded values. 661 662 @param type: Template type. See L{Types}. 663 @type type: str 664 @param name: Template name. 665 @type name: str 666 @param fields: Fields of keywods: {"name":"value"}. Changed by this 667 function to finded keywords. 668 @type fields: dict 669 @param srcfile: Source file, which editing into editor. 670 @type srcfile: str =C{''} 671 @param params: Additional parameters. (Usually for boa constructor its 672 'model' and 'view' objects). 673 @type params: dict = {} 674 @return: Parsed template, and changed fields (added new). 675 @rtype: str 676 """ 677 678 if not isinstance(fields, dict): 679 raise codetplArgumentError, 'Argument "fields" must be a dict.' 680 if not self.HasType(type): 681 raise codetplArgumentError, 'Unknown template type.' 682 self.__srcfile=srcfile 683 ##dbg.writeln('\n\tSRCFILE assign==', self.__srcfile) ##@ 684 type=type.lower() 685 name=name.lower() 686 if type=='kwd': 687 d=self.__kwds 688 n=name 689 else: 690 d=self.__tpls 691 n=type + '_' + name 692 if not d.has_key(n): 693 raise codetplArgumentError, 'No such template "' + n + '".' 694 # Safe call of template function. 695 try: 696 sys.modules[d[n].__module__].codetpl_sourcefile=self.__srcfile 697 sys.modules[d[n].__module__].codetpl_params=params 698 ## dbg.writeln('\n module dict== ', sys.modules[d[n].__module__].__dict__['codetpl_sourcefile']) ##@ 699 if type=='kwd': 700 tpl=d[n]() ## Must return str. 701 else: 702 tpl=d[n](fields) ## Must return str and changed or new fields. 703 except Exception, err: 704 e=codetplTemplateException('Exception in template: ' + str(err)) 705 e.Err=err 706 raise e 707 # If keywords then do not parse. 708 if type=='kwd': 709 return str(tpl) 710 # Use self.__kwds, borders is '@', case insensetive. 711 tpl=self.ReplaceTemplate(tpl, fields, None, '@', False, srcfile, params) 712 return tpl
713
714 - def ReplaceTemplate(self, tpl, fields, kwds=None, brds='@', case=False, \ 715 srcfile='', params={}):
716 """ 717 Parse template C{tpl}. Change all C{fields} rounded borders 718 C{brd} to value of C{fields}. If fields not find then try 719 search into C{kwds}. If not find then use fields key as value. 720 721 @param tpl: Template string to parse with fields. 722 @type tpl: str 723 @param fields: Fields for search and replace into C{tpl}. 724 @type fields: dict 725 @param kwds: Keywords for search if not find into C{fields}. 726 - If C{None} then use instance L{__kwds}. 727 - If dict then its value may be: 728 - str - use directly. 729 - function - call with no arguments, must return string. 730 @type kwds: B{None}, str or dict{key: str or func()} 731 @param brds: Borders wrapped around keys. 732 Twice brds is parsed as single character 'brds'. 733 @type brds: str = '@' 734 @param case: If True then keys is casesensetive. 735 @type case: boolean = False 736 @param srcfile: Source file, which editing into editor. 737 @type srcfile: str =C{''} 738 @param params: Additional parameters. (Usually for boa constructor its 739 'model' and 'view' objects). 740 @type params: dict = {} 741 @return: Replaced template, and changed fields (added new). 742 @rtype: str 743 """ 744 745 self.__srcfile=srcfile 746 # Pattern to match keys into templates. 747 if case: 748 flags=re.I | re.S 749 else: 750 flags=re.S 751 self.__ro=re.compile(r'(?<!'+brds+r')'+brds+r'\w+?' \ 752 +brds+r'(?!'+brds+r')', flags) 753 754 if kwds==None: 755 kwds=self.__kwds 756 # Convert keys to lower. 757 d=dict( [ (k.lower(), v) for k,v in fields.iteritems() ] ) 758 dk=dict( [ (k.lower(), v) for k,v in kwds.iteritems() ] ) 759 # Find all @???@ and plase into dict F. 760 ##tpl=str(tpl) # Only ANSY support. 761 tpl=unicode(tpl,errors='replace') #:PATCH: Unicode support. 762 ## dbg.writeln('-------FILL FIELDS-------') ##@ 763 764 #Removing "@" from sides and make lower. 765 F=[ k[1:-1] for k in self.__ro.findall(tpl) ] 766 ## dbg.writeln('F=%s' % (str(F),) ) ##@ 767 ## dbg.writeln('d=%s' % (str(d),) ) ##@ 768 ## dbg.writeln('dk=%s' % (str(dk),) ) ##@ 769 ## dbg.writeln('kwds=%s' % (str(kwds),) ) ##@ 770 771 # Calculate all F. 772 f={} 773 for kk in F: 774 k=kk.lower() 775 ## dbg.writeln(' try find field=%s' % (k,) ) ##@ 776 if d.has_key(k): 777 ##r=str(d[k]) # Only ANSY support. 778 r=unicode(d[k]) #:PATCH: Unicode support 779 ## dbg.writeln(' find field %s=%s' % (k,r) ) ##@ 780 ## dbg.write(' dict keyword %s=' % (str(dk),) ) ##@ 781 elif dk.has_key(k): 782 ## dbg.write(' find keyword %s=' % (k,) ) ##@ 783 if callable(dk[k]): 784 sys.modules[dk[k].__module__].codetpl_sourcefile=self.__srcfile 785 sys.modules[dk[k].__module__].codetpl_params=params 786 ## dbg.writeln( 'Module srcfile==', sys.modules[dk[k].__module__].codetpl_sourcefile) ##@ 787 ## dbg.writeln( 'Instance srcfile==', self.__srcfile) ##@ 788 ##r=str(dk[k]()) # Only ANSY support. 789 r=unicode(dk[k]()) #:PATCH: Unicode support. 790 ## dbg.writeln('func(%s)=%s' % (dk[k].__name__,r) ) ##@ 791 else: 792 r=str(dk[k]) 793 ## dbg.writeln('%s' % (r,) ) ##@ 794 else: 795 r=kk 796 ## dbg.writeln(' No such field, keyword') ##@ 797 f[k]=r 798 fields[kk]=r 799 ## dbg.writeln(' *** %s=%s' % (k,f[k]) ) ##@ 800 801 # Replace into tpl all F. 802 r=tpl 803 ro=re.compile(r'@@',re.I | re.S) 804 r=ro.sub('@',r) 805 for k in f: 806 ro=re.compile(r'(?<!@)@'+k+r'@(?!@)',re.I | re.S) 807 r=ro.sub(f[k],r) 808 # Remove first and last empty lines. 809 r=r.splitlines(True) 810 if r[0].strip()=='': 811 r.pop(0) 812 if r[-1].strip()=='': 813 r.pop(-1) 814 return ''.join(r)
815
816 - def HasType(self, type_):
817 """ 818 Test - has such type or not. 819 820 It's more perfomance then use I{C{'type' in Types}}, becouse 821 it use inner fields, then return copy. 822 823 C{type} are case insensetive (converts to lower). 824 825 @param type_: Tested template type. 826 @type type_: str 827 @return: C{True} if has, else C{False}. 828 @rtype: boolean. 829 """ 830 type_=type_.lower() 831 return type_ in self.__types
832
833 - def GetSourceFile(self):
834 """ 835 Get edited surce file. 836 837 @return: Source file path or C{''} if no. 838 @rtype: string 839 """ 840 return self.__srcfile
841 842 843 844 845 #-DEBUG-START------------------------------------------------------------------- 846
847 -def _debug():
848 """ 849 """ 850 pass
851 852 #-DEBUG-END--------------------------------------------------------------------- 853 854 if __name__=='__main__': 855 _debug() 856