././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1741830843.249475 markuppy-1.17/0000755000076500000240000000000000000000000013333 5ustar00tylerbakkestaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741827631.0 markuppy-1.17/LICENSE0000644000076500000240000000205400000000000014341 0ustar00tylerbakkestaffMIT License Copyright (c) 2017 Tyler Bakke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1741830843.2456677 markuppy-1.17/MarkupPy/0000755000076500000240000000000000000000000015103 5ustar00tylerbakkestaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741827631.0 markuppy-1.17/MarkupPy/__init__.py0000644000076500000240000000000000000000000017202 0ustar00tylerbakkestaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1741830817.0 markuppy-1.17/MarkupPy/markup.py0000644000076500000240000005375700000000000016775 0ustar00tylerbakkestaff# This code is in the public domain, it comes # with absolutely no warranty and you can do # absolutely whatever you want with it. __date__ = '12 March 2024' __version__ = '1.17' __doc__= """ This is markup.py - a Python module that attempts to make it easier to generate HTML/XML from a Python program in an intuitive, lightweight, customizable and pythonic way. It works with both python 2 and 3. The code is in the public domain. Version: %s as of %s. Documentation and further info is at http://markup.sourceforge.net/ Please send bug reports, feature requests, enhancement ideas or questions to nogradi at gmail dot com. Installation: drop markup.py somewhere into your Python path. """ % ( __version__, __date__ ) try: basestring import string except: # python 3 basestring = str string = str long = int # tags which are reserved python keywords will be referred # to by a leading underscore otherwise we end up with a syntax error import keyword class element: """This class handles the addition of a new element.""" def __init__( self, tag, case='lower', parent=None ): self.parent = parent if case == 'upper': self.tag = tag.upper( ) elif case == 'lower': self.tag = tag.lower( ) elif case =='given': self.tag = tag else: self.tag = tag def __call__( self, *args, **kwargs ): if len( args ) > 1: raise ArgumentError( self.tag ) # if class_ was defined in parent it should be added to every element if self.parent is not None and self.parent.class_ is not None: if 'class_' not in kwargs: kwargs['class_'] = self.parent.class_ if self.parent is None and len( args ) == 1: x = [ self.render( self.tag, False, myarg, mydict ) for myarg, mydict in _argsdicts( args, kwargs ) ] return '\n'.join( x ) elif self.parent is None and len( args ) == 0: x = [ self.render( self.tag, True, myarg, mydict ) for myarg, mydict in _argsdicts( args, kwargs ) ] return '\n'.join( x ) if self.tag in self.parent.twotags: for myarg, mydict in _argsdicts( args, kwargs ): self.render( self.tag, False, myarg, mydict ) elif self.tag in self.parent.onetags: if len( args ) == 0: for myarg, mydict in _argsdicts( args, kwargs ): self.render( self.tag, True, myarg, mydict ) # here myarg is always None, because len( args ) = 0 else: raise ClosingError( self.tag ) elif self.parent.mode == 'strict_html' and self.tag in self.parent.deptags: raise DeprecationError( self.tag ) else: raise InvalidElementError( self.tag, self.parent.mode ) def render( self, tag, single, between, kwargs ): """Append the actual tags to content.""" out = "<%s" % tag for key, value in list( kwargs.items( ) ): if value is not None: # when value is None that means stuff like <... checked> key = key.strip('_') # strip this so class_ will mean class, etc. if key == 'http_equiv': # special cases, maybe change _ to - overall? key = 'http-equiv' elif key == 'accept_charset': key = 'accept-charset' out = "%s %s=\"%s\"" % ( out, key, escape( value ) ) else: out = "%s %s" % ( out, key ) if between is not None: out = "%s>%s" % ( out, between, tag ) else: if single: out = "%s />" % out else: out = "%s>" % out if self.parent is not None: self.parent.content.append( out ) else: return out def close( self ): """Append a closing tag unless element has only opening tag.""" if self.tag in self.parent.twotags: self.parent.content.append( "" % self.tag ) elif self.tag in self.parent.onetags: raise ClosingError( self.tag ) elif self.parent.mode == 'strict_html' and self.tag in self.parent.deptags: raise DeprecationError( self.tag ) def open( self, **kwargs ): """Append an opening tag.""" if self.tag in self.parent.twotags or self.tag in self.parent.onetags: self.render( self.tag, False, None, kwargs ) elif self.mode == 'strict_html' and self.tag in self.parent.deptags: raise DeprecationError( self.tag ) class page: """This is our main class representing a document. Elements are added as attributes of an instance of this class.""" def __init__( self, mode='strict_html', case='lower', onetags=None, twotags=None, separator='\n', class_=None ): """Stuff that effects the whole document. mode -- 'strict_html' for HTML 4.01 (default) 'html' alias for 'strict_html' 'loose_html' to allow some deprecated elements 'xml' to allow arbitrary elements case -- 'lower' element names will be printed in lower case (default) 'upper' they will be printed in upper case 'given' element names will be printed as they are given onetags -- list or tuple of valid elements with opening tags only twotags -- list or tuple of valid elements with both opening and closing tags these two keyword arguments may be used to select the set of valid elements in 'xml' mode invalid elements will raise appropriate exceptions separator -- string to place between added elements, defaults to newline class_ -- a class that will be added to every element if defined""" valid_onetags = [ "AREA", "BASE", "BR", "COL", "FRAME", "HR", "IMG", "INPUT", "LINK", "META", "PARAM" ] valid_twotags = [ "A", "ABBR", "ACRONYM", "ADDRESS", "B", "BDO", "BIG", "BLOCKQUOTE", "BODY", "BUTTON", "CAPTION", "CITE", "CODE", "COLGROUP", "DD", "DEL", "DFN", "DIV", "DL", "DT", "EM", "FIELDSET", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HTML", "I", "IFRAME", "INS", "KBD", "LABEL", "LEGEND", "LI", "MAP", "NOFRAMES", "NOSCRIPT", "OBJECT", "OL", "OPTGROUP", "OPTION", "P", "PRE", "Q", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRONG", "STYLE", "SUB", "SUP", "TABLE", "TBODY", "TD", "TEXTAREA", "TFOOT", "TH", "THEAD", "TITLE", "TR", "TT", "UL", "VAR" ] deprecated_onetags = [ "BASEFONT", "ISINDEX" ] deprecated_twotags = [ "APPLET", "CENTER", "DIR", "FONT", "MENU", "S", "STRIKE", "U" ] self.header = [ ] self.content = [ ] self.footer = [ ] self.case = case self.separator = separator # init( ) sets it to True so we know that has to be printed at the end self._full = False self.class_= class_ if mode == 'strict_html' or mode == 'html': self.onetags = valid_onetags self.onetags += list( map( string.lower, self.onetags ) ) self.twotags = valid_twotags self.twotags += list( map( string.lower, self.twotags ) ) self.deptags = deprecated_onetags + deprecated_twotags self.deptags += list( map( string.lower, self.deptags ) ) self.mode = 'strict_html' elif mode == 'loose_html': self.onetags = valid_onetags + deprecated_onetags self.onetags += list( map( string.lower, self.onetags ) ) self.twotags = valid_twotags + deprecated_twotags self.twotags += list( map( string.lower, self.twotags ) ) self.mode = mode elif mode == 'xml': if onetags and twotags: self.onetags = onetags self.twotags = twotags elif ( onetags and not twotags ) or ( twotags and not onetags ): raise CustomizationError( ) else: self.onetags = russell( ) self.twotags = russell( ) self.mode = mode else: raise ModeError( mode ) def __getattr__( self, attr ): # tags should start with double underscore if attr.startswith("__") and attr.endswith("__"): raise AttributeError( attr ) # tag with single underscore should be a reserved keyword if attr.startswith( '_' ): attr = attr.lstrip( '_' ) if attr not in keyword.kwlist: raise AttributeError( attr ) return element( attr, case=self.case, parent=self ) def __str__( self ): if self._full and ( self.mode == 'strict_html' or self.mode == 'loose_html' ): end = [ '', '' ] else: end = [ ] return self.separator.join( self.header + self.content + self.footer + end ) def __call__( self, escape=False ): """Return the document as a string. escape -- False print normally True replace < and > by < and > the default escape sequences in most browsers""" if escape: return _escape( self.__str__( ) ) else: return self.__str__( ) def add( self, text ): """This is an alias to addcontent.""" self.addcontent( text ) def add_raw( self, text ): """Add text directly to the document without using the separator when rendering. This is useful for pre tags and other elements where you don't want extra newlines.""" if self.content and isinstance(self.content[-1], basestring): # Append to the last content item to avoid separator insertion self.content[-1] += text else: # Start a new content item self.content.append(text) def addfooter( self, text ): """Add some text to the bottom of the document""" self.footer.append( text ) def addheader( self, text ): """Add some text to the top of the document""" self.header.append( text ) def addcontent( self, text ): """Add some text to the main part of the document""" self.content.append( text ) def init( self, lang='en', css=None, metainfo=None, title=None, header=None, footer=None, charset=None, encoding=None, doctype=None, bodyattrs=None, script=None, base=None, style_content=None, script_content=None ): """This method is used for complete documents with appropriate doctype, encoding, title, etc information. For an HTML/XML snippet omit this method. lang -- language, usually a two character string, will appear as in html mode (ignored in xml mode) css -- Cascading Style Sheet filename as a string or a list of strings for multiple css files (ignored in xml mode) metainfo -- a dictionary in the form { 'name':'content' } to be inserted into meta element(s) as (ignored in xml mode) base -- set the tag in bodyattrs --a dictionary in the form { 'key':'value', ... } which will be added as attributes of the element as (ignored in xml mode) script -- dictionary containing src:type pairs, or a list of [ 'src1', 'src2', ... ] in which case 'javascript' is assumed for all title -- the title of the document as a string to be inserted into a title element as my title (ignored in xml mode) header -- some text to be inserted right after the element (ignored in xml mode) footer -- some text to be inserted right before the element (ignored in xml mode) charset -- a string defining the character set, will be inserted into a element (ignored in xml mode) encoding -- a string defining the encoding, will be put into to first line of the document as in xml mode (ignored in html mode) doctype -- the document type string, defaults to in html mode (ignored in xml mode) style_content -- CSS style content as a string or a list of strings to be inserted into