if "<STR_LIT:+>" in pieces.get("<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>return "<STR_LIT:.>"<EOL><DEDENT>return "<STR_LIT:+>"<EOL>

Return a + if we don't already have one, else return a .


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"] or pieces["<STR_LIT>"]:<EOL><INDENT>rendered += plus_or_dot(pieces)<EOL>rendered += "<STR_LIT>" % (pieces["<STR_LIT>"], pieces["<STR_LIT>"])<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % (pieces["<STR_LIT>"],<EOL>pieces["<STR_LIT>"])<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT>return rendered<EOL>

Build up version string, with post-release "local version identifier".

    Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
    get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty

    Exceptions:
    1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT>return rendered<EOL>

TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"] or pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>rendered += plus_or_dot(pieces)<EOL>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL><DEDENT>return rendered<EOL>

TAG[.postDISTANCE[.dev0]+gHEX] .

    The ".dev0" means dirty. Note that .dev0 sorts backwards
    (a dirty tree will appear "older" than the corresponding clean one),
    but you shouldn't be releasing software with -dirty anyways.

    Exceptions:
    1: no tags. 0.postDISTANCE[.dev0]


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"] or pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>rendered = "<STR_LIT>" % pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT><DEDENT>return rendered<EOL>

TAG[.postDISTANCE[.dev0]] .

    The ".dev0" means dirty.

    Eexceptions:
    1: no tags. 0.postDISTANCE[.dev0]


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>" % (pieces["<STR_LIT>"], pieces["<STR_LIT>"])<EOL><DEDENT><DEDENT>else:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL><DEDENT>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>return rendered<EOL>

TAG[-DISTANCE-gHEX][-dirty].

    Like 'git describe --tags --dirty --always'.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)


if pieces["<STR_LIT>"]:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL>rendered += "<STR_LIT>" % (pieces["<STR_LIT>"], pieces["<STR_LIT>"])<EOL><DEDENT>else:<EOL><INDENT>rendered = pieces["<STR_LIT>"]<EOL><DEDENT>if pieces["<STR_LIT>"]:<EOL><INDENT>rendered += "<STR_LIT>"<EOL><DEDENT>return rendered<EOL>

TAG-DISTANCE-gHEX[-dirty].

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)


if pieces["<STR_LIT:error>"]:<EOL><INDENT>return {"<STR_LIT:version>": "<STR_LIT>",<EOL>"<STR_LIT>": pieces.get("<STR_LIT>"),<EOL>"<STR_LIT>": None,<EOL>"<STR_LIT:error>": pieces["<STR_LIT:error>"],<EOL>"<STR_LIT:date>": None}<EOL><DEDENT>if not style or style == "<STR_LIT:default>":<EOL><INDENT>style = "<STR_LIT>"  <EOL><DEDENT>if style == "<STR_LIT>":<EOL><INDENT>rendered = render_pep440(pieces)<EOL><DEDENT>elif style == "<STR_LIT>":<EOL><INDENT>rendered = render_pep440_pre(pieces)<EOL><DEDENT>elif style == "<STR_LIT>":<EOL><INDENT>rendered = render_pep440_post(pieces)<EOL><DEDENT>elif style == "<STR_LIT>":<EOL><INDENT>rendered = render_pep440_old(pieces)<EOL><DEDENT>elif style == "<STR_LIT>":<EOL><INDENT>rendered = render_git_describe(pieces)<EOL><DEDENT>elif style == "<STR_LIT>":<EOL><INDENT>rendered = render_git_describe_long(pieces)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>" % style)<EOL><DEDENT>return {"<STR_LIT:version>": rendered, "<STR_LIT>": pieces["<STR_LIT>"],<EOL>"<STR_LIT>": pieces["<STR_LIT>"], "<STR_LIT:error>": None,<EOL>"<STR_LIT:date>": pieces.get("<STR_LIT:date>")}<EOL>

Render the given version pieces into the requested style.


if "<STR_LIT>" in sys.modules:<EOL><INDENT>del sys.modules["<STR_LIT>"]<EOL><DEDENT>root = get_root()<EOL>cfg = get_config_from_root(root)<EOL>assert cfg.VCS is not None, "<STR_LIT>"<EOL>handlers = HANDLERS.get(cfg.VCS)<EOL>assert handlers, "<STR_LIT>" % cfg.VCS<EOL>verbose = verbose or cfg.verbose<EOL>assert cfg.versionfile_source is not None,"<STR_LIT>"<EOL>assert cfg.tag_prefix is not None, "<STR_LIT>"<EOL>versionfile_abs = os.path.join(root, cfg.versionfile_source)<EOL>get_keywords_f = handlers.get("<STR_LIT>")<EOL>from_keywords_f = handlers.get("<STR_LIT>")<EOL>if get_keywords_f and from_keywords_f:<EOL><INDENT>try:<EOL><INDENT>keywords = get_keywords_f(versionfile_abs)<EOL>ver = from_keywords_f(keywords, cfg.tag_prefix, verbose)<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % ver)<EOL><DEDENT>return ver<EOL><DEDENT>except NotThisMethod:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>try:<EOL><INDENT>ver = versions_from_file(versionfile_abs)<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % (versionfile_abs, ver))<EOL><DEDENT>return ver<EOL><DEDENT>except NotThisMethod:<EOL><INDENT>pass<EOL><DEDENT>from_vcs_f = handlers.get("<STR_LIT>")<EOL>if from_vcs_f:<EOL><INDENT>try:<EOL><INDENT>pieces = from_vcs_f(cfg.tag_prefix, root, verbose)<EOL>ver = render(pieces, cfg.style)<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % ver)<EOL><DEDENT>return ver<EOL><DEDENT>except NotThisMethod:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>try:<EOL><INDENT>if cfg.parentdir_prefix:<EOL><INDENT>ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose)<EOL>if verbose:<EOL><INDENT>print("<STR_LIT>" % ver)<EOL><DEDENT>return ver<EOL><DEDENT><DEDENT>except NotThisMethod:<EOL><INDENT>pass<EOL><DEDENT>if verbose:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>return {"<STR_LIT:version>": "<STR_LIT>", "<STR_LIT>": None,<EOL>"<STR_LIT>": None, "<STR_LIT:error>": "<STR_LIT>",<EOL>"<STR_LIT:date>": None}<EOL>

Get the project version from whatever source is available.

    Returns dict with two keys: 'version' and 'full'.


return get_versions()["<STR_LIT:version>"]<EOL>

Get the short version string for this project.


if "<STR_LIT>" in sys.modules:<EOL><INDENT>del sys.modules["<STR_LIT>"]<EOL><DEDENT>cmds = {}<EOL>from distutils.core import Command<EOL>class cmd_version(Command):<EOL><INDENT>description = "<STR_LIT>"<EOL>user_options = []<EOL>boolean_options = []<EOL>def initialize_options(self):<EOL><INDENT>pass<EOL><DEDENT>def finalize_options(self):<EOL><INDENT>pass<EOL><DEDENT>def run(self):<EOL><INDENT>vers = get_versions(verbose=True)<EOL>print("<STR_LIT>" % vers["<STR_LIT:version>"])<EOL>print("<STR_LIT>" % vers.get("<STR_LIT>"))<EOL>print("<STR_LIT>" % vers.get("<STR_LIT>"))<EOL>print("<STR_LIT>" % vers.get("<STR_LIT:date>"))<EOL>if vers["<STR_LIT:error>"]:<EOL><INDENT>print("<STR_LIT>" % vers["<STR_LIT:error>"])<EOL><DEDENT><DEDENT><DEDENT>cmds["<STR_LIT:version>"] = cmd_version<EOL>if "<STR_LIT>" in sys.modules:<EOL><INDENT>from setuptools.command.build_py import build_py as _build_py<EOL><DEDENT>else:<EOL><INDENT>from distutils.command.build_py import build_py as _build_py<EOL><DEDENT>class cmd_build_py(_build_py):<EOL><INDENT>def run(self):<EOL><INDENT>root = get_root()<EOL>cfg = get_config_from_root(root)<EOL>versions = get_versions()<EOL>_build_py.run(self)<EOL>if cfg.versionfile_build:<EOL><INDENT>target_versionfile = os.path.join(self.build_lib,<EOL>cfg.versionfile_build)<EOL>print("<STR_LIT>" % target_versionfile)<EOL>write_to_version_file(target_versionfile, versions)<EOL><DEDENT><DEDENT><DEDENT>cmds["<STR_LIT>"] = cmd_build_py<EOL>if "<STR_LIT>" in sys.modules:  <EOL><INDENT>from cx_Freeze.dist import build_exe as _build_exe<EOL>class cmd_build_exe(_build_exe):<EOL><INDENT>def run(self):<EOL><INDENT>root = get_root()<EOL>cfg = get_config_from_root(root)<EOL>versions = get_versions()<EOL>target_versionfile = cfg.versionfile_source<EOL>print("<STR_LIT>" % target_versionfile)<EOL>write_to_version_file(target_versionfile, versions)<EOL>_build_exe.run(self)<EOL>os.unlink(target_versionfile)<EOL>with open(cfg.versionfile_source, "<STR_LIT:w>") as f:<EOL><INDENT>LONG = LONG_VERSION_PY[cfg.VCS]<EOL>f.write(LONG %<EOL>{"<STR_LIT>": "<STR_LIT:$>",<EOL>"<STR_LIT>": cfg.style,<EOL>"<STR_LIT>": cfg.tag_prefix,<EOL>"<STR_LIT>": cfg.parentdir_prefix,<EOL>"<STR_LIT>": cfg.versionfile_source,<EOL>})<EOL><DEDENT><DEDENT><DEDENT>cmds["<STR_LIT>"] = cmd_build_exe<EOL>del cmds["<STR_LIT>"]<EOL><DEDENT>if '<STR_LIT>' in sys.modules:  <EOL><INDENT>try:<EOL><INDENT>from py2exe.distutils_buildexe import py2exe as _py2exe  <EOL><DEDENT>except ImportError:<EOL><INDENT>from py2exe.build_exe import py2exe as _py2exe  <EOL><DEDENT>class cmd_py2exe(_py2exe):<EOL><INDENT>def run(self):<EOL><INDENT>root = get_root()<EOL>cfg = get_config_from_root(root)<EOL>versions = get_versions()<EOL>target_versionfile = cfg.versionfile_source<EOL>print("<STR_LIT>" % target_versionfile)<EOL>write_to_version_file(target_versionfile, versions)<EOL>_py2exe.run(self)<EOL>os.unlink(target_versionfile)<EOL>with open(cfg.versionfile_source, "<STR_LIT:w>") as f:<EOL><INDENT>LONG = LONG_VERSION_PY[cfg.VCS]<EOL>f.write(LONG %<EOL>{"<STR_LIT>": "<STR_LIT:$>",<EOL>"<STR_LIT>": cfg.style,<EOL>"<STR_LIT>": cfg.tag_prefix,<EOL>"<STR_LIT>": cfg.parentdir_prefix,<EOL>"<STR_LIT>": cfg.versionfile_source,<EOL>})<EOL><DEDENT><DEDENT><DEDENT>cmds["<STR_LIT>"] = cmd_py2exe<EOL><DEDENT>if "<STR_LIT>" in sys.modules:<EOL><INDENT>from setuptools.command.sdist import sdist as _sdist<EOL><DEDENT>else:<EOL><INDENT>from distutils.command.sdist import sdist as _sdist<EOL><DEDENT>class cmd_sdist(_sdist):<EOL><INDENT>def run(self):<EOL><INDENT>versions = get_versions()<EOL>self._versioneer_generated_versions = versions<EOL>self.distribution.metadata.version = versions["<STR_LIT:version>"]<EOL>return _sdist.run(self)<EOL><DEDENT>def make_release_tree(self, base_dir, files):<EOL><INDENT>root = get_root()<EOL>cfg = get_config_from_root(root)<EOL>_sdist.make_release_tree(self, base_dir, files)<EOL>target_versionfile = os.path.join(base_dir, cfg.versionfile_source)<EOL>print("<STR_LIT>" % target_versionfile)<EOL>write_to_version_file(target_versionfile,<EOL>self._versioneer_generated_versions)<EOL><DEDENT><DEDENT>cmds["<STR_LIT>"] = cmd_sdist<EOL>return cmds<EOL>

Get the custom setuptools/distutils subclasses used by Versioneer.


root = get_root()<EOL>try:<EOL><INDENT>cfg = get_config_from_root(root)<EOL><DEDENT>except (EnvironmentError, configparser.NoSectionError,<EOL>configparser.NoOptionError) as e:<EOL><INDENT>if isinstance(e, (EnvironmentError, configparser.NoSectionError)):<EOL><INDENT>print("<STR_LIT>",<EOL>file=sys.stderr)<EOL>with open(os.path.join(root, "<STR_LIT>"), "<STR_LIT:a>") as f:<EOL><INDENT>f.write(SAMPLE_CONFIG)<EOL><DEDENT><DEDENT>print(CONFIG_ERROR, file=sys.stderr)<EOL>return <NUM_LIT:1><EOL><DEDENT>print("<STR_LIT>" % cfg.versionfile_source)<EOL>with open(cfg.versionfile_source, "<STR_LIT:w>") as f:<EOL><INDENT>LONG = LONG_VERSION_PY[cfg.VCS]<EOL>f.write(LONG % {"<STR_LIT>": "<STR_LIT:$>",<EOL>"<STR_LIT>": cfg.style,<EOL>"<STR_LIT>": cfg.tag_prefix,<EOL>"<STR_LIT>": cfg.parentdir_prefix,<EOL>"<STR_LIT>": cfg.versionfile_source,<EOL>})<EOL><DEDENT>ipy = os.path.join(os.path.dirname(cfg.versionfile_source),<EOL>"<STR_LIT>")<EOL>if os.path.exists(ipy):<EOL><INDENT>try:<EOL><INDENT>with open(ipy, "<STR_LIT:r>") as f:<EOL><INDENT>old = f.read()<EOL><DEDENT><DEDENT>except EnvironmentError:<EOL><INDENT>old = "<STR_LIT>"<EOL><DEDENT>if INIT_PY_SNIPPET not in old:<EOL><INDENT>print("<STR_LIT>" % ipy)<EOL>with open(ipy, "<STR_LIT:a>") as f:<EOL><INDENT>f.write(INIT_PY_SNIPPET)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % ipy)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>" % ipy)<EOL>ipy = None<EOL><DEDENT>manifest_in = os.path.join(root, "<STR_LIT>")<EOL>simple_includes = set()<EOL>try:<EOL><INDENT>with open(manifest_in, "<STR_LIT:r>") as f:<EOL><INDENT>for line in f:<EOL><INDENT>if line.startswith("<STR_LIT>"):<EOL><INDENT>for include in line.split()[<NUM_LIT:1>:]:<EOL><INDENT>simple_includes.add(include)<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>except EnvironmentError:<EOL><INDENT>pass<EOL><DEDENT>if "<STR_LIT>" not in simple_includes:<EOL><INDENT>print("<STR_LIT>")<EOL>with open(manifest_in, "<STR_LIT:a>") as f:<EOL><INDENT>f.write("<STR_LIT>")<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>if cfg.versionfile_source not in simple_includes:<EOL><INDENT>print("<STR_LIT>" %<EOL>cfg.versionfile_source)<EOL>with open(manifest_in, "<STR_LIT:a>") as f:<EOL><INDENT>f.write("<STR_LIT>" % cfg.versionfile_source)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL><DEDENT>do_vcs_install(manifest_in, cfg.versionfile_source, ipy)<EOL>return <NUM_LIT:0><EOL>

Main VCS-independent setup function for installing Versioneer.


found = set()<EOL>setters = False<EOL>errors = <NUM_LIT:0><EOL>with open("<STR_LIT>", "<STR_LIT:r>") as f:<EOL><INDENT>for line in f.readlines():<EOL><INDENT>if "<STR_LIT>" in line:<EOL><INDENT>found.add("<STR_LIT>")<EOL><DEDENT>if "<STR_LIT>" in line:<EOL><INDENT>found.add("<STR_LIT>")<EOL><DEDENT>if "<STR_LIT>" in line:<EOL><INDENT>found.add("<STR_LIT>")<EOL><DEDENT>if "<STR_LIT>" in line:<EOL><INDENT>setters = True<EOL><DEDENT>if "<STR_LIT>" in line:<EOL><INDENT>setters = True<EOL><DEDENT><DEDENT><DEDENT>if len(found) != <NUM_LIT:3>:<EOL><INDENT>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>errors += <NUM_LIT:1><EOL><DEDENT>if setters:<EOL><INDENT>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>print("<STR_LIT>")<EOL>errors += <NUM_LIT:1><EOL><DEDENT>return errors<EOL>

Validate the contents of setup.py against Versioneer's expectations.


return "<STR_LIT>".format(self.message, self.error_code, self.error_text)<EOL>

Define string representation of the CloudStackClientException
:return: String containing a message, the error code as well as the error text
:rtype: str


return str(self)<EOL>

Define representation of the CloudStackClientException
:return: String containing a message, the error code as well as the error text
:rtype: str


def __init__(self, end_point: str, api_key: str, api_secret: str, event_loop: asyncio.AbstractEventLoop,<EOL>async_poll_latency: int=<NUM_LIT:2>, max_page_size: int=<NUM_LIT>) -> None:

self.end_point = end_point<EOL>self.api_key = api_key<EOL>self.api_secret = api_secret<EOL>self.event_loop = event_loop<EOL>self.async_poll_latency = async_poll_latency<EOL>self.max_page_size = max_page_size<EOL>self.client_session = aiohttp.ClientSession(loop=self.event_loop)<EOL>

Client object to access a CloudStack API

:param end_point: URL to reach the CloudStack API
:type end_point: str
:param api_key: APIKey to access the CloudStack API (usually available from your cloud provider)
:type api_key: str
:param api_secret: Secret to access the CloudStack API (usually available from your cloud provider)
:param event_loop: asyncio event loop to utilize
:type event_loop: asyncio.AbstractEventLoop
:param async_poll_latency: Time in seconds to wait before polling CloudStack API to fetch results of
                           asynchronous API calls
:type async_poll_latency: int
:param max_page_size: Some API calls are paginated like listVirtualMachines, this number specifies the maximum
                      number of item returned in one API call. The client automatically takes care of the
                      pagination by splitting it into separate API calls and returns the entire list
:type max_page_size: int

:Example:

.. code-block:: python

   event_loop = asyncio.get_event_loop()
   cloud_stack_client = CloudStack(end_point='https://api.exoscale.ch/compute',
                                   api_key='<Your API key>',
                                   api_secret='Your API secret',
                                   event_loop=event_loop)


try:<EOL><INDENT>self.event_loop.run_until_complete(self._close_session())<EOL><DEDENT>except RuntimeError:<EOL><INDENT>self.event_loop.create_task(self._close_session())<EOL><DEDENT>

Deletion function taking care that the used sessions is closed before the deleting the object. This is
mandatory according to the aiohttp documentation. The deletion function is thus scheduling a task that takes
care of closing the session. Depending wether an event loop is already running, the task is either scheduled or
a new event loop is started.


await self.client_session.close()<EOL>await asyncio.sleep(<NUM_LIT>)<EOL>

According to the aiohttp documentation all opened sessions need to be closed, before leaving the program. This
function takes care that the client session is closed. This async co-routine is automatically scheduled, when
the client object is destroyed.


def __getattr__(self, command: str) -> Callable:

return partial(self.request, command=command)<EOL>

This allows to support any available and future CloudStack API in this client. The returned partial function can
directly be used to call the corresponding CloudStack API including all supported parameters.

:param command: Command string indicating the CloudStack API to be called.
:type command: str
:return: Partial function that can be used the call the CloudStack API specified in the command string.


async def request(self, command: str, **kwargs) -> dict:

kwargs.update(dict(apikey=self.api_key, command=command, response='<STR_LIT>'))<EOL>if '<STR_LIT:list>' in command.lower():  <EOL><INDENT>kwargs.update(dict(pagesize=self.max_page_size, page=<NUM_LIT:1>))<EOL><DEDENT>final_data = dict()<EOL>while True:<EOL><INDENT>async with self.client_session.get(self.end_point, params=self._sign(kwargs)) as response:<EOL><INDENT>data = await self._handle_response(response=response,<EOL>await_final_result='<STR_LIT>' not in command.lower())<EOL>try:<EOL><INDENT>count = data.pop('<STR_LIT:count>')<EOL><DEDENT>except KeyError:<EOL><INDENT>if not data:<EOL><INDENT>return final_data<EOL><DEDENT>else:<EOL><INDENT>return data<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for key, value in data.items():<EOL><INDENT>final_data.setdefault(key, []).extend(value)<EOL><DEDENT>final_data['<STR_LIT:count>'] = final_data.setdefault('<STR_LIT:count>', <NUM_LIT:0>) + count<EOL>kwargs['<STR_LIT>'] += <NUM_LIT:1><EOL>if count < self.max_page_size:  <EOL><INDENT>return final_data<EOL><DEDENT><DEDENT><DEDENT><DEDENT>

Async co-routine to perform requests to a CloudStackAPI. The parameters needs to include the command string,
which refers to the API to be called. In principle any available and future CloudStack API can be called. The
`**kwargs` magic allows us to all add supported parameters to the given API call. A list of all available APIs
can found at https://cloudstack.apache.org/api/apidocs-4.8/TOC_User.html

:param command: Command string indicating the CloudStack API to be called.
:type command: str
:param kwargs: Parameters to be passed to the CloudStack API
:return: Dictionary containing the decoded json reply of the CloudStack API
:rtype: dict


async def _handle_response(self, response: aiohttp.client_reqrep.ClientResponse, await_final_result: bool) -> dict:

try:<EOL><INDENT>data = await response.json()<EOL><DEDENT>except aiohttp.client_exceptions.ContentTypeError:<EOL><INDENT>text = await response.text()<EOL>logging.debug('<STR_LIT>'.format(text))<EOL>raise CloudStackClientException(message="<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>data = self._transform_data(data)<EOL>if response.status != <NUM_LIT:200>:<EOL><INDENT>raise CloudStackClientException(message="<STR_LIT>",<EOL>error_code=data.get("<STR_LIT>", response.status),<EOL>error_text=data.get("<STR_LIT>"),<EOL>response=data)<EOL><DEDENT><DEDENT>while await_final_result and ('<STR_LIT>' in data):<EOL><INDENT>await asyncio.sleep(self.async_poll_latency)<EOL>data = await self.queryAsyncJobResult(jobid=data['<STR_LIT>'])<EOL>if data['<STR_LIT>']:  <EOL><INDENT>if not data['<STR_LIT>']:  <EOL><INDENT>try:<EOL><INDENT>return data['<STR_LIT>']<EOL><DEDENT>except KeyError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>logging.debug("<STR_LIT>".format(str(data)))<EOL>raise CloudStackClientException(message="<STR_LIT>",<EOL>error_code=data.get("<STR_LIT>"),<EOL>error_text=data.get("<STR_LIT>"),<EOL>response=data)<EOL><DEDENT><DEDENT>return data<EOL>

Handles the response returned from the CloudStack API. Some CloudStack API are implemented asynchronous, which
means that the API call returns just a job id. The actually expected API response is postponed and a specific
asyncJobResults API has to be polled using the job id to get the final result once the API call has been
processed.

:param response: The response returned by the aiohttp call.
:type response: aiohttp.client_reqrep.ClientResponse
:param await_final_result: Specifier that indicates whether the function should poll the asyncJobResult API
                           until the asynchronous API call has been processed
:type await_final_result: bool
:return: Dictionary containing the JSON response of the API call
:rtype: dict


def _sign(self, url_parameters: dict) -> dict:

if url_parameters:<EOL><INDENT>url_parameters.pop('<STR_LIT>', None)  <EOL>request_string = urlencode(sorted(url_parameters.items()), safe='<STR_LIT>', quote_via=quote).lower()<EOL>digest = hmac.new(self.api_secret.encode('<STR_LIT:utf-8>'), request_string.encode('<STR_LIT:utf-8>'), hashlib.sha1).digest()<EOL>url_parameters['<STR_LIT>'] = base64.b64encode(digest).decode('<STR_LIT:utf-8>').strip()<EOL><DEDENT>return url_parameters<EOL>

According to the CloudStack documentation, each request needs to be signed in order to authenticate the user
account executing the API command. The signature is generated using a combination of the api secret and a SHA-1
hash of the url parameters including the command string. In order to generate a unique identifier, the url
parameters have to be transformed to lower case and ordered alphabetically.

:param url_parameters: The url parameters of the API call including the command string
:type url_parameters: dict
:return: The url parameters including a new key, which contains the signature
:rtype: dict


@staticmethod<EOL><INDENT>def _transform_data(data: dict) -> dict:<DEDENT>

for key in data.keys():<EOL><INDENT>return_value = data[key]<EOL>if isinstance(return_value, dict):<EOL><INDENT>return return_value<EOL><DEDENT><DEDENT>return data<EOL>

Each CloudStack API call returns a nested dictionary structure. The first level contains only one key indicating
the API that originated the response. This function removes that first level from the data returned to the
caller.

:param data: Response of the API call
:type data: dict
:return: Simplified response without the information about the API that originated the response.
:rtype: dict


self.callbacks = dict()<EOL>self.default_callback = None<EOL>if _telemetry_use_c_api:<EOL><INDENT>self.api = TelemetryCBinding(transport,self._on_frame)<EOL><DEDENT>else:<EOL><INDENT>self.api = Telemetry(transport,self._on_frame)<EOL><DEDENT>

Creates a new instance of the Pytelemetry class.

:param transport: A transport-compliant class. See Pytelemetry class
documentation for more information


self.api.delimiter.resetStats()<EOL>self.api.resetStats()<EOL>

Resets all counters that monitor transport and protocol to 0.


d = dict()<EOL>d['<STR_LIT>'] = self.api.delimiter.stats()<EOL>d['<STR_LIT>'] = self.api.stats()<EOL>return d<EOL>

Returns a dictionnary of dictionnary that contains critical information
about the transport and protocol behavior, such as:
   * amount of received frames
   * amount of badly delimited frames
   * amount of correctly delimited but still corrupted frames
   * etc


return next(START_TAG_FINDITER(string))<EOL>

Return the first found match of START_TAG_FINDITER.


def _plant_trie(strings: _List[str]) -> dict:

<EOL>trie = {}<EOL>for string in strings:<EOL><INDENT>d = trie<EOL>for char in string:<EOL><INDENT>d[char] = char in d and d[char] or {}<EOL>d = d[char]<EOL><DEDENT>d['<STR_LIT>'] = None  <EOL><DEDENT>return trie<EOL>

Create a Trie out of a list of words and return an atomic regex pattern.

    The corresponding Regex should match much faster than a simple Regex union.


if '<STR_LIT>' in trie:<EOL><INDENT>if len(trie) == <NUM_LIT:1>:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>optional = True<EOL>del trie['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>optional = False<EOL><DEDENT>subpattern_to_chars = _defaultdict(list)<EOL>for char, sub_trie in trie.items():<EOL><INDENT>subpattern = _pattern(sub_trie)<EOL>subpattern_to_chars[subpattern].append(char)<EOL><DEDENT>alts = []<EOL>for subpattern, chars in subpattern_to_chars.items():<EOL><INDENT>if len(chars) == <NUM_LIT:1>:<EOL><INDENT>alts.append(chars[<NUM_LIT:0>] + subpattern)<EOL><DEDENT>else:<EOL><INDENT>chars.sort(reverse=True)<EOL>alts.append('<STR_LIT:[>' + '<STR_LIT>'.join(chars) + '<STR_LIT:]>' + subpattern)<EOL><DEDENT><DEDENT>if len(alts) == <NUM_LIT:1>:<EOL><INDENT>result = alts[<NUM_LIT:0>]<EOL>if optional:<EOL><INDENT>if len(result) == <NUM_LIT:1>:<EOL><INDENT>result += '<STR_LIT>'<EOL><DEDENT>else:  <EOL><INDENT>result = '<STR_LIT>' + result + '<STR_LIT>'<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>alts.sort(reverse=True)<EOL>result = '<STR_LIT>' + '<STR_LIT:|>'.join(alts) + '<STR_LIT:)>'<EOL>if optional:<EOL><INDENT>result += '<STR_LIT>'<EOL><DEDENT><DEDENT>return result<EOL>


def regex_pattern(words: _List[str]) -> str:

return _pattern(_plant_trie(words))<EOL>

Convert words to a regex pattern that matches any of them.


def __init__(<EOL>self,<EOL>string: Union[str, MutableSequence[str]],<EOL>header: bool = False,<EOL>_type_to_spans: Dict[str, List[List[int]]] = None,<EOL>_span: int = None,<EOL>_type: int = None,<EOL>_match: Match = None,<EOL>_attrs_match: Match = None,<EOL>) -> None:

super().__init__(string, _type_to_spans, _span, _type)<EOL>self._header = header<EOL>if _match:<EOL><INDENT>string = self.string<EOL>self._match_cache = _match, string<EOL>if _attrs_match:<EOL><INDENT>self._attrs_match_cache = _attrs_match, string<EOL><DEDENT>else:<EOL><INDENT>self._attrs_match_cache =ATTRS_MATCH(_match['<STR_LIT>']), string<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self._attrs_match_cache = self._match_cache = None, None<EOL><DEDENT>


cache_match, cache_string = self._match_cache<EOL>string = self.string<EOL>if cache_string == string:<EOL><INDENT>return cache_match<EOL><DEDENT>shadow = self._shadow<EOL>if shadow[<NUM_LIT:0>] == <NUM_LIT:10>:  <EOL><INDENT>m = NEWLINE_CELL_MATCH(shadow)<EOL>self._header = m['<STR_LIT>'] == <NUM_LIT>  <EOL><DEDENT>elif self._header:<EOL><INDENT>m = INLINE_HAEDER_CELL_MATCH(shadow)<EOL><DEDENT>else:<EOL><INDENT>m = INLINE_NONHAEDER_CELL_MATCH(shadow)<EOL><DEDENT>self._match_cache = m, string<EOL>self._attrs_match_cache = None, None<EOL>return m<EOL>

Return the match object for the current tag. Cache the result.

        Be extra careful when using this property. The position of match
        may be something other than zero if the match is cached from the
        parent object (the initial value).


@property<EOL><INDENT>def value(self) -> str:<DEDENT>

m = self._match<EOL>offset = m.start()<EOL>s, e = m.span('<STR_LIT:data>')<EOL>return self[s - offset:e - offset]<EOL>


@value.setter<EOL><INDENT>def value(self, new_value: str) -> None:<DEDENT>

m = self._match<EOL>offset = m.start()<EOL>s, e = m.span('<STR_LIT:data>')<EOL>self[s - offset:e - offset] = new_value<EOL>


cache, cache_string = self._attrs_match_cache<EOL>string = self.string<EOL>if cache_string == string:<EOL><INDENT>return cache<EOL><DEDENT>s, e = self._match.span('<STR_LIT>')<EOL>attrs_match = ATTRS_MATCH(self._shadow, s, e)<EOL>self._attrs_match_cache = attrs_match, string<EOL>return attrs_match<EOL>


def set_attr(self, attr_name: str, attr_value: str) -> None:

<EOL>cell_match = self._match<EOL>shadow = cell_match.string<EOL>attrs_start, attrs_end = cell_match.span('<STR_LIT>')<EOL>if attrs_start != -<NUM_LIT:1>:<EOL><INDENT>encoded_attr_name = attr_name.encode()<EOL>attrs_m = ATTRS_MATCH(shadow, attrs_start, attrs_end)<EOL>for i, n in enumerate(reversed(attrs_m.captures('<STR_LIT>'))):<EOL><INDENT>if n == encoded_attr_name:<EOL><INDENT>vs, ve = attrs_m.spans('<STR_LIT>')[-i - <NUM_LIT:1>]<EOL>q = <NUM_LIT:1> if attrs_m.string[ve] in b'<STR_LIT>' else <NUM_LIT:0><EOL>self[vs - q:ve + q] = '<STR_LIT>'.format(attr_value)<EOL>return<EOL><DEDENT><DEDENT>attr_end = cell_match.end('<STR_LIT>')<EOL>fmt = '<STR_LIT>' if shadow[attr_end - <NUM_LIT:1>] == <NUM_LIT:32> else '<STR_LIT>'<EOL>self.insert(attr_end, fmt.format(attr_name, attr_value))<EOL>return<EOL><DEDENT>fmt = '<STR_LIT>' if attr_value else '<STR_LIT>'<EOL>if shadow[<NUM_LIT:0>] == <NUM_LIT:10>:  <EOL><INDENT>self.insert(<EOL>cell_match.start('<STR_LIT>') + <NUM_LIT:1>,<EOL>fmt.format(attr_name, attr_value)<EOL>)<EOL>return<EOL><DEDENT>self.insert(<NUM_LIT:2>, fmt.format(attr_name, attr_value))<EOL>return<EOL>

Set the value for the given attribute name.

        If there are already multiple attributes with that name, only
        set the value for the last one.
        If attr_value == '', use the implicit empty attribute syntax.


@property<EOL><INDENT>def target(self) -> str:<DEDENT>

head, pipe, tail = self._atomic_partition(<NUM_LIT>)<EOL>if pipe:<EOL><INDENT>return head[<NUM_LIT:2>:]<EOL><DEDENT>else:<EOL><INDENT>return head[<NUM_LIT:2>:-<NUM_LIT:2>]<EOL><DEDENT>


@target.setter<EOL><INDENT>def target(self, newtarget: str) -> None:<DEDENT>

head, pipe, tail = self._atomic_partition(<NUM_LIT>)<EOL>if not pipe:<EOL><INDENT>head = head[:-<NUM_LIT:2>]<EOL><DEDENT>self[<NUM_LIT:2>:len(head)] = newtarget<EOL>


@property<EOL><INDENT>def text(self) -> Optional[str]:<DEDENT>

head, pipe, tail = self._atomic_partition(<NUM_LIT>)<EOL>if pipe:<EOL><INDENT>return tail[:-<NUM_LIT:2>]<EOL><DEDENT>return None<EOL>

Return the text of this WikiLink. Do not include linktrail.


@text.setter<EOL><INDENT>def text(self, newtext: Optional[str]) -> None:<DEDENT>

head, pipe, tail = self._atomic_partition(<NUM_LIT>)<EOL>if pipe:<EOL><INDENT>if newtext is None:<EOL><INDENT>del self[len(head + pipe) - <NUM_LIT:1>:len(head + pipe + tail) - <NUM_LIT:2>]<EOL><DEDENT>else:<EOL><INDENT>self[len(head + pipe):len(head + pipe + tail) - <NUM_LIT:2>] = newtext<EOL><DEDENT><DEDENT>elif newtext is not None:<EOL><INDENT>self.insert(-<NUM_LIT:2>, '<STR_LIT:|>' + newtext)<EOL><DEDENT>

Set self.text to newtext. Remove it if newtext is None.

        Do not change the linktrail.


@property<EOL><INDENT>def contents(self) -> str:<DEDENT>

return self.string[<NUM_LIT:4>:-<NUM_LIT:3>]<EOL>


@property<EOL><INDENT>def name(self) -> str:<DEDENT>

lststr0 = self._lststr[<NUM_LIT:0>]<EOL>ss = self._span[<NUM_LIT:0>]<EOL>shadow_match = self._shadow_match<EOL>if shadow_match['<STR_LIT>']:<EOL><INDENT>s, e = shadow_match.span('<STR_LIT>')<EOL>return lststr0[ss + s:ss + e]<EOL><DEDENT>position = <NUM_LIT:1><EOL>for s, e in self._type_to_spans[self._type]:<EOL><INDENT>if ss <= s:<EOL><INDENT>break<EOL><DEDENT>arg_str = lststr0[s:e]<EOL>if '<STR_LIT:=>' in arg_str:<EOL><INDENT>byte_array = bytearray(arg_str, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>parse_to_spans(byte_array)  <EOL>if b'<STR_LIT:=>' in byte_array:<EOL><INDENT>continue<EOL><DEDENT><DEDENT>position += <NUM_LIT:1><EOL><DEDENT>return str(position)<EOL>

Return argument's name.

        For positional arguments return the position as a string.


@name.setter<EOL><INDENT>def name(self, newname: str) -> None:<DEDENT>

oldname = self.name<EOL>if self._shadow_match['<STR_LIT>']:<EOL><INDENT>self[<NUM_LIT:1>:<NUM_LIT:1> + len(oldname)] = newname<EOL><DEDENT>else:<EOL><INDENT>self[<NUM_LIT:0>:<NUM_LIT:1>] = '<STR_LIT:|>' + newname + '<STR_LIT:=>'<EOL><DEDENT>

Set the name for this argument.

        If this is a positional argument, convert it to keyword argument.


@property<EOL><INDENT>def positional(self) -> bool:<DEDENT>

return False if self._shadow_match['<STR_LIT>'] else True<EOL>

Return True if there is an equal sign in the argument else False.


@positional.setter<EOL><INDENT>def positional(self, to_positional: bool) -> None:<DEDENT>

shadow_match = self._shadow_match<EOL>if shadow_match['<STR_LIT>']:<EOL><INDENT>if to_positional:<EOL><INDENT>del self[<NUM_LIT:1>:shadow_match.end('<STR_LIT>')]<EOL><DEDENT>else:<EOL><INDENT>return<EOL><DEDENT><DEDENT>if to_positional:<EOL><INDENT>return<EOL><DEDENT>raise ValueError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>

Change to keyword or positional accordingly.

        Raise ValueError on trying to convert positional to keyword argument.


shadow_match = self._shadow_match<EOL>if shadow_match['<STR_LIT>']:<EOL><INDENT>return self[shadow_match.start('<STR_LIT>'):]<EOL><DEDENT>return self[<NUM_LIT:1>:]<EOL>


@value.setter<EOL><INDENT>def value(self, newvalue: str) -> None:<DEDENT>

shadow_match = self._shadow_match<EOL>if shadow_match['<STR_LIT>']:<EOL><INDENT>self[shadow_match.start('<STR_LIT>'):] = newvalue<EOL><DEDENT>else:<EOL><INDENT>self[<NUM_LIT:1>:] = newvalue<EOL><DEDENT>


return max(set(list_), key=list_.count)<EOL>

Return the most common item in the list.

    Return the first one if there are more than one most common items.

    Example:

    >>> mode([1,1,2,2,])
    1
    >>> mode([1,2,2])
    2
    >>> mode([])
    ...
    ValueError: max() arg is an empty sequence


def get_arg(name: str, args: Iterable[Argument]) -> Optional[Argument]:

for arg in args:<EOL><INDENT>if arg.name.strip(WS) == name.strip(WS):<EOL><INDENT>return arg<EOL><DEDENT><DEDENT>return None<EOL>

Return the first argument in the args that has the given name.

    Return None if no such argument is found.

    As the computation of self.arguments is a little costly, this
    function was created so that other methods that have already computed
    the arguments use it instead of calling self.get_arg directly.


def normal_name(<EOL>self,<EOL>rm_namespaces=('<STR_LIT>',),<EOL>capital_links=False,<EOL>_code: str = None,<EOL>*,<EOL>code: str = None,<EOL>capitalize=False<EOL>) -> str:

if capital_links:<EOL><INDENT>warn('<STR_LIT>'<EOL>'<STR_LIT>', DeprecationWarning)<EOL>capitalize = capital_links<EOL><DEDENT>if _code:<EOL><INDENT>warn('<STR_LIT>'<EOL>'<STR_LIT>', DeprecationWarning)<EOL>code = _code<EOL><DEDENT>name = COMMENT_SUB('<STR_LIT>', self.name).strip(WS)<EOL>if code:<EOL><INDENT>head, sep, tail = name.partition('<STR_LIT::>')<EOL>if not head and sep:<EOL><INDENT>name = tail.strip('<STR_LIT:U+0020>')<EOL>head, sep, tail = name.partition('<STR_LIT::>')<EOL><DEDENT>if code.lower() == head.strip('<STR_LIT:U+0020>').lower():<EOL><INDENT>name = tail.strip('<STR_LIT:U+0020>')<EOL><DEDENT><DEDENT>head, sep, tail = name.partition('<STR_LIT::>')<EOL>if not head and sep:<EOL><INDENT>name = tail.strip('<STR_LIT:U+0020>')<EOL>head, sep, tail = name.partition('<STR_LIT::>')<EOL><DEDENT>if head:<EOL><INDENT>ns = head.strip('<STR_LIT:U+0020>').lower()<EOL>for namespace in rm_namespaces:<EOL><INDENT>if namespace.lower() == ns:<EOL><INDENT>name = tail.strip('<STR_LIT:U+0020>')<EOL>break<EOL><DEDENT><DEDENT><DEDENT>name = name.replace('<STR_LIT:_>', '<STR_LIT:U+0020>')<EOL>if capitalize:<EOL><INDENT>n0 = name[<NUM_LIT:0>]<EOL>if n0.islower():<EOL><INDENT>name = n0.upper() + name[<NUM_LIT:1>:]<EOL><DEDENT><DEDENT>name, sep, tail = name.partition('<STR_LIT:#>')<EOL>return '<STR_LIT:U+0020>'.join(name.split())<EOL>

Return normal form of self.name.

        - Remove comments.
        - Remove language code.
        - Remove namespace ("template:" or any of `localized_namespaces`.
        - Use space instead of underscore.
        - Remove consecutive spaces.
        - Use uppercase for the first letter if `capitalize`.
        - Remove #anchor.

        :param rm_namespaces: is used to provide additional localized
            namespaces for the template namespace. They will be removed from
            the result. Default is ('Template',).
        :param capitalize: If True, convert the first letter of the
            template's name to a capital letter. See
            [[mw:Manual:$wgCapitalLinks]] for more info.
        :param code: is the language code.
        :param capital_links: deprecated.
        :param _code: deprecated.

        Example:
            >>> Template(
            ...     '{{ eN : tEmPlAtE : <!-- c --> t_1 # b | a }}'
            ... ).normal_name(code='en')
            'T 1'


names = set()  <EOL>for a in reversed(self.arguments):<EOL><INDENT>name = a.name.strip(WS)<EOL>if name in names:<EOL><INDENT>del a[:len(a.string)]<EOL><DEDENT>else:<EOL><INDENT>names.add(name)<EOL><DEDENT><DEDENT>

Eliminate duplicate arguments by removing the first occurrences.

        Remove the first occurrences of duplicate arguments, regardless of
        their value. Result of the rendered wikitext should remain the same.
        Warning: Some meaningful data may be removed from wikitext.

        Also see `rm_dup_args_safe` function.


def rm_dup_args_safe(self, tag: str = None) -> None:

name_to_lastarg_vals = {}<EOL>for arg in reversed(self.arguments):<EOL><INDENT>name = arg.name.strip(WS)<EOL>if arg.positional:<EOL><INDENT>val = arg.value<EOL><DEDENT>else:<EOL><INDENT>val = arg.value.strip(WS)<EOL><DEDENT>if name in name_to_lastarg_vals:<EOL><INDENT>if not val:<EOL><INDENT>del arg[<NUM_LIT:0>:len(arg.string)]<EOL><DEDENT>else:<EOL><INDENT>lastarg, dup_vals = name_to_lastarg_vals[name]<EOL>if val in dup_vals:<EOL><INDENT>del arg[<NUM_LIT:0>:len(arg.string)]<EOL><DEDENT>elif '<STR_LIT>' in dup_vals:<EOL><INDENT>del lastarg[<NUM_LIT:0>:len(lastarg.string)]<EOL>dup_vals.pop(<NUM_LIT:0>)<EOL><DEDENT>else:<EOL><INDENT>dup_vals.append(val)<EOL>if tag:<EOL><INDENT>arg.value += tag<EOL><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>name_to_lastarg_vals[name] = (arg, [val])<EOL><DEDENT><DEDENT>

Remove duplicate arguments in a safe manner.

        Remove the duplicate arguments only in the following situations:
            1. Both arguments have the same name AND value. (Remove one of
                them.)
            2. Arguments have the same name and one of them is empty. (Remove
                the empty one.)

        Warning: Although this is considered to be safe and no meaningful data
            is removed from wikitext, but the result of the rendered wikitext
            may actually change if the second arg is empty and removed but
            the first had had a value.

        If `tag` is defined, it should be a string that will be appended to
        the value of the remaining duplicate arguments.

        Also see `rm_first_of_dup_args` function.


def set_arg(<EOL>self, name: str,<EOL>value: str,<EOL>positional: bool = None,<EOL>before: str = None,<EOL>after: str = None,<EOL>preserve_spacing: bool = True<EOL>) -> None:

args = list(reversed(self.arguments))<EOL>arg = get_arg(name, args)<EOL>if arg:<EOL><INDENT>if positional:<EOL><INDENT>arg.positional = positional<EOL><DEDENT>if preserve_spacing:<EOL><INDENT>val = arg.value<EOL>arg.value = val.replace(val.strip(WS), value)<EOL><DEDENT>else:<EOL><INDENT>arg.value = value<EOL><DEDENT>return<EOL><DEDENT>if not name and positional is None:<EOL><INDENT>positional = True<EOL><DEDENT>if not positional and preserve_spacing and args:<EOL><INDENT>before_names = []<EOL>name_lengths = []<EOL>before_values = []<EOL>after_values = []<EOL>for arg in args:<EOL><INDENT>aname = arg.name<EOL>name_len = len(aname)<EOL>name_lengths.append(name_len)<EOL>before_names.append(STARTING_WS_MATCH(aname)[<NUM_LIT:0>])<EOL>arg_value = arg.value<EOL>before_values.append(STARTING_WS_MATCH(arg_value)[<NUM_LIT:0>])<EOL>after_values.append(ENDING_WS_MATCH(arg_value)[<NUM_LIT:0>])<EOL><DEDENT>pre_name_ws_mode = mode(before_names)<EOL>name_length_mode = mode(name_lengths)<EOL>post_value_ws_mode = mode(<EOL>[SPACE_AFTER_SEARCH(self.string)[<NUM_LIT:0>]] + after_values[<NUM_LIT:1>:]<EOL>)<EOL>pre_value_ws_mode = mode(before_values)<EOL><DEDENT>else:<EOL><INDENT>preserve_spacing = False<EOL><DEDENT>if positional:<EOL><INDENT>addstring = '<STR_LIT:|>' + value<EOL><DEDENT>else:<EOL><INDENT>if preserve_spacing:<EOL><INDENT>addstring = (<EOL>'<STR_LIT:|>' + (pre_name_ws_mode + name.strip(WS)).<EOL>ljust(name_length_mode) +<EOL>'<STR_LIT:=>' + pre_value_ws_mode + value + post_value_ws_mode<EOL>)<EOL><DEDENT>else:<EOL><INDENT>addstring = '<STR_LIT:|>' + name + '<STR_LIT:=>' + value<EOL><DEDENT><DEDENT>if before:<EOL><INDENT>arg = get_arg(before, args)<EOL>arg.insert(<NUM_LIT:0>, addstring)<EOL><DEDENT>elif after:<EOL><INDENT>arg = get_arg(after, args)<EOL>arg.insert(len(arg.string), addstring)<EOL><DEDENT>else:<EOL><INDENT>if args and not positional:<EOL><INDENT>arg = args[<NUM_LIT:0>]<EOL>arg_string = arg.string<EOL>if preserve_spacing:<EOL><INDENT>arg[<NUM_LIT:0>:len(arg_string)] = (<EOL>arg.string.rstrip(WS) + post_value_ws_mode +<EOL>addstring.rstrip(WS) + after_values[<NUM_LIT:0>]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>arg.insert(len(arg_string), addstring)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self.insert(-<NUM_LIT:2>, addstring)<EOL><DEDENT><DEDENT>

Set the value for `name` argument. Add it if it doesn't exist.

        - Use `positional`, `before` and `after` keyword arguments only when
          adding a new argument.
        - If `before` is given, ignore `after`.
        - If neither `before` nor `after` are given and it's needed to add a
          new argument, then append the new argument to the end.
        - If `positional` is True, try to add the given value as a positional
          argument. Ignore `preserve_spacing` if positional is True.
          If it's None, do what seems more appropriate.


def get_arg(self, name: str) -> Optional[Argument]:

return get_arg(name, reversed(self.arguments))<EOL>

Return the last argument with the given name.

        Return None if no argument with that name is found.


def has_arg(self, name: str, value: str = None) -> bool:

for arg in reversed(self.arguments):<EOL><INDENT>if arg.name.strip(WS) == name.strip(WS):<EOL><INDENT>if value:<EOL><INDENT>if arg.positional:<EOL><INDENT>if arg.value == value:<EOL><INDENT>return True<EOL><DEDENT>return False<EOL><DEDENT>if arg.value.strip(WS) == value.strip(WS):<EOL><INDENT>return True<EOL><DEDENT>return False<EOL><DEDENT>return True<EOL><DEDENT><DEDENT>return False<EOL>

Return true if the is an arg named `name`.

        Also check equality of values if `value` is provided.

        Note: If you just need to get an argument and you want to LBYL, it's
            better to get_arg directly and then check if the returned value
            is None.


for arg in reversed(self.arguments):<EOL><INDENT>if arg.name.strip(WS) == name.strip(WS):<EOL><INDENT>del arg[:]<EOL><DEDENT><DEDENT>

Delete all arguments with the given then.


def parse_to_spans(byte_array: bytearray) -> Dict[str, List[List[int]]]:

comment_spans = []  <EOL>comment_spans_append = comment_spans.append<EOL>extension_tag_spans = []  <EOL>extension_tag_spans_append = extension_tag_spans.append<EOL>wikilink_spans = []  <EOL>wikilink_spans_append = wikilink_spans.append<EOL>parameter_spans = []  <EOL>parameter_spans_append = parameter_spans.append<EOL>parser_function_spans = []  <EOL>parser_function_spans_append = parser_function_spans.append<EOL>template_spans = []  <EOL>template_spans_append = template_spans.append<EOL>for match in COMMENT_FINDITER(byte_array):<EOL><INDENT>ms, me = match.span()<EOL>comment_spans_append([ms, me])<EOL>byte_array[ms:me] = b'<STR_LIT:U+0020>' * (me - ms)<EOL><DEDENT>for match in EXTENSION_TAGS_FINDITER(byte_array):<EOL><INDENT>ms, me = match.span()<EOL>extension_tag_spans_append([ms, me])<EOL>if match[<NUM_LIT:2>]:  <EOL><INDENT>parse_tag_extensions(<EOL>byte_array, ms, me,<EOL>wikilink_spans_append,<EOL>parameter_spans_append,<EOL>parser_function_spans_append,<EOL>template_spans_append)<EOL><DEDENT>byte_array[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL><DEDENT>while True:<EOL><INDENT>match = None<EOL>for match in WIKILINK_FINDITER(byte_array):<EOL><INDENT>ms, me = match.span()<EOL>wikilink_spans_append([ms, me])<EOL>parse_pm_pf_tl(<EOL>byte_array, ms, me,<EOL>parameter_spans_append,<EOL>parser_function_spans_append,<EOL>template_spans_append)<EOL>byte_array[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL><DEDENT>if match is None:<EOL><INDENT>break<EOL><DEDENT><DEDENT>parse_pm_pf_tl(<EOL>byte_array, <NUM_LIT:0>, None,<EOL>parameter_spans_append,<EOL>parser_function_spans_append,<EOL>template_spans_append)<EOL>return {<EOL>'<STR_LIT>': sorted(comment_spans),<EOL>'<STR_LIT>': sorted(extension_tag_spans),<EOL>'<STR_LIT>': sorted(parameter_spans),<EOL>'<STR_LIT>': sorted(parser_function_spans),<EOL>'<STR_LIT>': sorted(template_spans),<EOL>'<STR_LIT>': sorted(wikilink_spans)}<EOL>

Calculate and set self._type_to_spans.

    The result is a dictionary containing lists of spans:
    {
        'Comment': comment_spans,
        'ExtTag': extension_tag_spans,
        'Parameter': parameter_spans,
        'ParserFunction': parser_function_spans,
        'Template': template_spans,
        'WikiLink': wikilink_spans,
    }


def parse_tag_extensions(<EOL>byte_array: bytearray,<EOL>start: int,<EOL>end: int,<EOL>wikilink_spans_append: Callable,<EOL>parameter_spans_append: Callable,<EOL>pfunction_spans_append: Callable,<EOL>template_spans_append: Callable,<EOL>) -> None:

while True:<EOL><INDENT>match = None<EOL>for match in WIKILINK_FINDITER(byte_array, start, end):<EOL><INDENT>ms, me = match.span()<EOL>wikilink_spans_append([ms, me])<EOL>parse_pm_pf_tl(<EOL>byte_array, ms, me,<EOL>parameter_spans_append,<EOL>pfunction_spans_append,<EOL>template_spans_append)<EOL>byte_array[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL><DEDENT>if match is None:<EOL><INDENT>break<EOL><DEDENT><DEDENT>parse_pm_pf_tl(<EOL>byte_array, start, end,<EOL>parameter_spans_append,<EOL>pfunction_spans_append,<EOL>template_spans_append)<EOL>

Parse the byte_array to spans.

    This function is basically the same as `parse_to_spans`, but accepts an
    start that indicates the starting start of the given byte_array.
    `byte_array`s that are passed to this function are the contents of
    PARSABLE_TAG_EXTENSIONS.


def parse_pm_pf_tl(<EOL>byte_array: bytearray, start: int, end: Optional[int],<EOL>parameter_spans_append: Callable,<EOL>pfunction_spans_append: Callable,<EOL>template_spans_append: Callable,<EOL>) -> None:

while True:<EOL><INDENT>for m in SINGLE_BRACES_FINDITER(byte_array, start, end):<EOL><INDENT>byte_array[m.start()] = <NUM_LIT>  <EOL><DEDENT>match = None<EOL>for match in PM_PF_TL_FINDITER(byte_array, start, end):<EOL><INDENT>ms, me = match.span()<EOL>if match[<NUM_LIT:1>] is not None:<EOL><INDENT>parameter_spans_append([ms, me])<EOL><DEDENT>elif match[<NUM_LIT:2>] is not None:<EOL><INDENT>pfunction_spans_append([ms, me])<EOL><DEDENT>elif match[<NUM_LIT:3>] is not None:  <EOL><INDENT>byte_array[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL>continue<EOL><DEDENT>else:<EOL><INDENT>template_spans_append([ms, me])<EOL><DEDENT>byte_array[ms:me] = b'<STR_LIT:X>' * (me - ms)<EOL><DEDENT>if match is None:<EOL><INDENT>return<EOL><DEDENT><DEDENT>

Find the spans of parameters, parser functions, and templates.

    :byte_array: The byte_array or part of byte_array that is being parsed.
    :start: Add to every returned start.

    This is the innermost loop of the parse_to_spans function.
    If the byte_array passed to parse_to_spans contains n WikiLinks, then
    this function will be called n + 1 times. One time for the whole byte_array
    and n times for each of the n WikiLinks.


name, pipe, default = self._atomic_partition(<NUM_LIT>)<EOL>if pipe:<EOL><INDENT>return name[<NUM_LIT:3>:]<EOL><DEDENT>return name[<NUM_LIT:3>:-<NUM_LIT:3>]<EOL>


self[<NUM_LIT:3>:<NUM_LIT:3> + len(self.name)] = newname<EOL>


@property<EOL><INDENT>def pipe(self) -> str:<DEDENT>

return self._atomic_partition(<NUM_LIT>)[<NUM_LIT:1>]<EOL>

Return `|` if there is a pipe (default value) in the Parameter.

        Return '' otherwise.


@property<EOL><INDENT>def default(self) -> Optional[str]:<DEDENT>

name, pipe, default = self._atomic_partition(<NUM_LIT>)<EOL>if pipe:<EOL><INDENT>return default[:-<NUM_LIT:3>]<EOL><DEDENT>return None<EOL>

Return the default value. Return None if there is no default.


@default.setter<EOL><INDENT>def default(self, newdefault: Optional[str]) -> None:<DEDENT>

name, pipe, default = self._atomic_partition(<NUM_LIT>)<EOL>if not pipe:<EOL><INDENT>if newdefault is None:<EOL><INDENT>return<EOL><DEDENT>self.insert(-<NUM_LIT:3>, '<STR_LIT:|>' + newdefault)<EOL>return<EOL><DEDENT>if newdefault is None:<EOL><INDENT>del self[len(name):-<NUM_LIT:3>]<EOL>return<EOL><DEDENT>self[len(name):-<NUM_LIT:3>] = '<STR_LIT:|>' + newdefault<EOL>

Set a new default value. Use None to remove default.


def append_default(self, new_default_name: str) -> None:

stripped_default_name = new_default_name.strip(WS)<EOL>if stripped_default_name == self.name.strip(WS):<EOL><INDENT>return<EOL><DEDENT>dig = True<EOL>innermost_param = self<EOL>while dig:<EOL><INDENT>dig = False<EOL>default = innermost_param.default<EOL>for p in innermost_param.parameters:<EOL><INDENT>if p.string == default:<EOL><INDENT>if stripped_default_name == p.name.strip(WS):<EOL><INDENT>return<EOL><DEDENT>innermost_param = p<EOL>dig = True<EOL><DEDENT><DEDENT><DEDENT>innermost_default = innermost_param.default<EOL>if innermost_default is None:<EOL><INDENT>innermost_param.insert(-<NUM_LIT:3>, '<STR_LIT>' + new_default_name + '<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>name = innermost_param.name<EOL>innermost_param[<EOL>len('<STR_LIT>' + name + '<STR_LIT:|>'):<EOL>len('<STR_LIT>' + name + '<STR_LIT:|>' + innermost_default)<EOL>] = '<STR_LIT>' + new_default_name + '<STR_LIT:|>' + innermost_default + '<STR_LIT>'<EOL><DEDENT>

Append a new default parameter in the appropriate place.

        Add the new default to the innter-most parameter.
        If the parameter already exists among defaults, don't change anything.

        Example:
            >>> p = Parameter('{{{p1|{{{p2|}}}}}}')
            >>> p.append_default('p3')
            >>> p
            Parameter("'{{{p1|{{{p2|{{{p3|}}}}}}}}}'")


@property<EOL><INDENT>def url(self) -> str:<DEDENT>

if self[<NUM_LIT:0>] == '<STR_LIT:[>':<EOL><INDENT>return self[<NUM_LIT:1>:URL_MATCH(self._ext_link_shadow, <NUM_LIT:1>).end()]<EOL><DEDENT>return self.string<EOL>


@url.setter<EOL><INDENT>def url(self, newurl: str) -> None:<DEDENT>

if self[<NUM_LIT:0>] == '<STR_LIT:[>':<EOL><INDENT>self[<NUM_LIT:1>:len('<STR_LIT:[>' + self.url)] = newurl<EOL><DEDENT>else:<EOL><INDENT>self[<NUM_LIT:0>:len(self.url)] = newurl<EOL><DEDENT>


@property<EOL><INDENT>def text(self) -> Optional[str]:<DEDENT>

string = self.string<EOL>if string[<NUM_LIT:0>] == '<STR_LIT:[>':<EOL><INDENT>end_match = URL_MATCH(self._ext_link_shadow, <NUM_LIT:1>)<EOL>url_end = end_match.end()<EOL>end_char = string[url_end]<EOL>if end_char == '<STR_LIT:]>':<EOL><INDENT>return None<EOL><DEDENT>if end_char == '<STR_LIT:U+0020>':<EOL><INDENT>return string[url_end + <NUM_LIT:1>:-<NUM_LIT:1>]<EOL><DEDENT>return string[url_end:-<NUM_LIT:1>]<EOL><DEDENT>

Return the text part (the part after the first space).

        Return None if this is a bare link or has no associated text.


@text.setter<EOL><INDENT>def text(self, newtext: str) -> None:<DEDENT>

string = self.string<EOL>if string[<NUM_LIT:0>] == '<STR_LIT:[>':<EOL><INDENT>text = self.text<EOL>if text:<EOL><INDENT>self[-len(text) - <NUM_LIT:1>:-<NUM_LIT:1>] = newtext<EOL>return<EOL><DEDENT>self.insert(-<NUM_LIT:1>, '<STR_LIT:U+0020>' + newtext)<EOL>return<EOL><DEDENT>self.insert(len(string), '<STR_LIT:U+0020>' + newtext + '<STR_LIT:]>')<EOL>self.insert(<NUM_LIT:0>, '<STR_LIT:[>')<EOL>

Set a new text.

        Automatically put the ExternalLink in brackets if it's not already.


@property<EOL><INDENT>def in_brackets(self) -> bool:<DEDENT>

return self[<NUM_LIT:0>] == '<STR_LIT:[>'<EOL>

Return true if the ExternalLink is in brackets. False otherwise.


@property<EOL><INDENT>def level(self) -> int:<DEDENT>

m = HEADER_MATCH(self._shadow)<EOL>if m:<EOL><INDENT>return len(m.group(<NUM_LIT:1>))<EOL><DEDENT>return <NUM_LIT:0><EOL>

Return level of this section.

        Level is in range(1,7) or 0 for the lead section.


@level.setter<EOL><INDENT>def level(self, value: int) -> None:<DEDENT>

old_level = self.level<EOL>title = self.title<EOL>new_equals = '<STR_LIT:=>' * value<EOL>self[<NUM_LIT:0>:old_level + len(title) + old_level] =new_equals + title + new_equals<EOL>


@property<EOL><INDENT>def title(self) -> str:<DEDENT>

level = self.level<EOL>if level == <NUM_LIT:0>:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>return self._atomic_partition(<NUM_LIT:10>)[<NUM_LIT:0>].rstrip(WS)[level:-level]<EOL>

Return title of this section. Return '' for lead sections.


@title.setter<EOL><INDENT>def title(self, value: str) -> None:<DEDENT>

level = self.level<EOL>if level == <NUM_LIT:0>:<EOL><INDENT>raise RuntimeError(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>)<EOL><DEDENT>title = self.title<EOL>self[level:level + len(title)] = value<EOL>

Set the new title for this section and update self.lststr.


@property<EOL><INDENT>def contents(self) -> str:<DEDENT>

if self.level == <NUM_LIT:0>:<EOL><INDENT>return self.string<EOL><DEDENT>return self._atomic_partition(<NUM_LIT:10>)[<NUM_LIT:2>]<EOL>


@contents.setter<EOL><INDENT>def contents(self, value: str) -> None:<DEDENT>

level = self.level<EOL>if level == <NUM_LIT:0>:<EOL><INDENT>self[:] = value<EOL>return<EOL><DEDENT>contents = self.contents<EOL>start = level + len(self.title) + level + <NUM_LIT:1><EOL>self[start:start + len(contents)] = value<EOL>

Set value as the contents of this section.


def _apply_attr_spans(<EOL>table_attrs: List[List[Dict[str, str]]], table_data: List[List[T]]<EOL>) -> List[List[T]]:

<EOL>xwidth = <NUM_LIT:0><EOL>yheight = <NUM_LIT:0><EOL>table = []  <EOL>ycurrent = <NUM_LIT:0><EOL>downward_growing_cells = []  <EOL>for attrs_row, row in zip(table_attrs, table_data):<EOL><INDENT>if yheight == ycurrent:<EOL><INDENT>yheight += <NUM_LIT:1><EOL>table.append([None] * xwidth)<EOL><DEDENT>xcurrent = <NUM_LIT:0><EOL>for cell, cellx, width in downward_growing_cells:<EOL><INDENT>r = table[ycurrent]<EOL>for x in range(cellx, cellx + width):<EOL><INDENT>r[x] = cell<EOL><DEDENT><DEDENT>for attrs, current_cell in zip(attrs_row, row):<EOL><INDENT>attrs_get = attrs.get<EOL>while (<EOL>xcurrent < xwidth and<EOL>table[ycurrent][xcurrent] is not None<EOL>):<EOL><INDENT>xcurrent += <NUM_LIT:1><EOL><DEDENT>if xcurrent == xwidth:<EOL><INDENT>xwidth += <NUM_LIT:1><EOL>for r in table:<EOL><INDENT>if xwidth > len(r):<EOL><INDENT>r.extend([None] * (xwidth - len(r)))<EOL><DEDENT><DEDENT><DEDENT>colspan = int(attrs_get(b'<STR_LIT>', <NUM_LIT:1>))<EOL>if colspan == <NUM_LIT:0>:<EOL><INDENT>colspan = <NUM_LIT:1><EOL><DEDENT>rowspan = int(attrs_get(b'<STR_LIT>', <NUM_LIT:1>))<EOL>if rowspan == <NUM_LIT:0>:<EOL><INDENT>cell_grows_downward = True<EOL>rowspan = <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>cell_grows_downward = False<EOL><DEDENT>if xwidth < xcurrent + colspan:<EOL><INDENT>xwidth = xcurrent + colspan<EOL>for r in table:<EOL><INDENT>if xwidth > len(r):<EOL><INDENT>r.extend([None] * (xwidth - len(r)))<EOL><DEDENT><DEDENT><DEDENT>if yheight < ycurrent + rowspan:<EOL><INDENT>yheight = ycurrent + rowspan<EOL>while len(table) < yheight:<EOL><INDENT>table.append([None] * xwidth)<EOL><DEDENT><DEDENT>for y in range(ycurrent, ycurrent + rowspan):<EOL><INDENT>r = table[y]<EOL>for x in range(xcurrent, xcurrent + colspan):<EOL><INDENT>r[x] = current_cell<EOL><DEDENT><DEDENT>if cell_grows_downward:<EOL><INDENT>downward_growing_cells.append(<EOL>(current_cell, xcurrent, colspan)<EOL>)<EOL><DEDENT>xcurrent += colspan<EOL><DEDENT>ycurrent += <NUM_LIT:1><EOL><DEDENT>while ycurrent < yheight:<EOL><INDENT>for cell, cellx, width in downward_growing_cells:<EOL><INDENT>for x in range(cellx, cellx + width):<EOL><INDENT>table[ycurrent][x] = cell<EOL><DEDENT><DEDENT>ycurrent += <NUM_LIT:1><EOL><DEDENT>return table<EOL>

Apply row and column spans and return table_data.


def _lstrip_increase(shadow: bytearray, pos: int) -> int:

length = len(shadow)<EOL>while pos < length and shadow[pos:pos + <NUM_LIT:1>].isspace():<EOL><INDENT>pos += <NUM_LIT:1><EOL><DEDENT>return pos<EOL>

Return the new position to lstrip the shadow.


def _semi_caption_increase(shadow: bytearray, pos: int) -> int:

lsp = _lstrip_increase(shadow, pos)<EOL>while shadow[lsp:lsp + <NUM_LIT:2>] == b'<STR_LIT>':<EOL><INDENT>pos = shadow.find(<NUM_LIT:10>, lsp + <NUM_LIT:2>)  <EOL>lsp = _lstrip_increase(shadow, pos)<EOL>while shadow[lsp] not in b'<STR_LIT>':<EOL><INDENT>nlp = shadow.find(<NUM_LIT:10>, lsp + <NUM_LIT:1>)  <EOL>pos = nlp<EOL>lsp = _lstrip_increase(shadow, nlp)<EOL><DEDENT><DEDENT>return pos<EOL>

Return the position after the starting semi-caption.

    Captions are optional and only one should be placed between table-start
    and the first row. Others captions are not part of the table and will
    be ignored. We call these semi-captions.


def _row_separator_increase(shadow: bytearray, pos: int) -> int:

<EOL>scp = _semi_caption_increase(shadow, pos)<EOL>lsp = _lstrip_increase(shadow, scp)<EOL>while shadow[lsp:lsp + <NUM_LIT:2>] == b'<STR_LIT>':<EOL><INDENT>pos = shadow.find(<NUM_LIT:10>, lsp + <NUM_LIT:2>)  <EOL>pos = _semi_caption_increase(shadow, pos)<EOL>lsp = _lstrip_increase(shadow, pos)<EOL><DEDENT>return pos<EOL>

Return the position after the starting row separator line.

    Also skips any semi-caption lines before and after the separator.


@property<EOL><INDENT>def _match_table(self) -> List[List[Any]]:<DEDENT>

shadow = self._shadow<EOL>pos = shadow.find(<NUM_LIT:10>)  <EOL>lsp = _lstrip_increase(shadow, pos)<EOL>while shadow[lsp] not in b'<STR_LIT>':<EOL><INDENT>nlp = shadow.find(<NUM_LIT:10>, lsp)  <EOL>pos = nlp<EOL>lsp = _lstrip_increase(shadow, pos)<EOL><DEDENT>match_table = []<EOL>pos = _semi_caption_increase(shadow, pos)<EOL>rsp = _row_separator_increase(shadow, pos)<EOL>pos = -<NUM_LIT:1><EOL>while pos != rsp:<EOL><INDENT>pos = rsp<EOL>m = NEWLINE_CELL_MATCH(shadow, pos)<EOL>if m:<EOL><INDENT>match_row = []  <EOL>match_table.append(match_row)<EOL>while m:<EOL><INDENT>match_row.append(m)<EOL>sep = m['<STR_LIT>']<EOL>pos = m.end()<EOL>if sep == b'<STR_LIT:|>':<EOL><INDENT>m = INLINE_NONHAEDER_CELL_MATCH(shadow, pos)<EOL>while m:<EOL><INDENT>match_row.append(m)<EOL>pos = m.end()<EOL>m = INLINE_NONHAEDER_CELL_MATCH(shadow, pos)<EOL><DEDENT><DEDENT>elif sep == b'<STR_LIT:!>':<EOL><INDENT>m = INLINE_HAEDER_CELL_MATCH(shadow, pos)<EOL>while m:<EOL><INDENT>match_row.append(m)<EOL>pos = m.end()<EOL>m = INLINE_HAEDER_CELL_MATCH(shadow, pos)<EOL><DEDENT><DEDENT>pos = _semi_caption_increase(shadow, pos)<EOL>m = NEWLINE_CELL_MATCH(shadow, pos)<EOL><DEDENT><DEDENT>rsp = _row_separator_increase(shadow, pos)<EOL><DEDENT>return match_table<EOL>


def data(<EOL>self, span: bool = True,<EOL>strip: bool = True,<EOL>row: int = None,<EOL>column: int = None<EOL>) -> Union[List[List[str]], List[str], str]:

match_table = self._match_table<EOL>string = self.string<EOL>table_data = []  <EOL>if strip:<EOL><INDENT>for match_row in match_table:<EOL><INDENT>row_data = []  <EOL>table_data.append(row_data)<EOL>for m in match_row:<EOL><INDENT>s, e = m.span('<STR_LIT:data>')<EOL>row_data.append(string[s:e].lstrip('<STR_LIT:U+0020>').rstrip(WS))<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for match_row in match_table:<EOL><INDENT>row_data = []<EOL>table_data.append(row_data)<EOL>for m in match_row:<EOL><INDENT>s, e = m.span('<STR_LIT:data>')<EOL>row_data.append(string[s:e])<EOL><DEDENT><DEDENT><DEDENT>if table_data:<EOL><INDENT>if span:<EOL><INDENT>table_attrs = []  <EOL>for match_row in match_table:<EOL><INDENT>row_attrs = []  <EOL>table_attrs.append(row_attrs)<EOL>row_attrs_append = row_attrs.append<EOL>for m in match_row:<EOL><INDENT>s, e = m.span('<STR_LIT>')<EOL>captures = ATTRS_MATCH(<EOL>string.encode('<STR_LIT:ascii>', '<STR_LIT:replace>'), s, e).captures<EOL>row_attrs_append(dict(zip(<EOL>captures('<STR_LIT>'), captures('<STR_LIT>')<EOL>)))<EOL><DEDENT><DEDENT>table_data = _apply_attr_spans(table_attrs, table_data)<EOL><DEDENT><DEDENT>if row is None:<EOL><INDENT>if column is None:<EOL><INDENT>return table_data<EOL><DEDENT>return [r[column] for r in table_data]<EOL><DEDENT>if column is None:<EOL><INDENT>return table_data[row]<EOL><DEDENT>return table_data[row][column]<EOL>

Return a list containing lists of row values.

        :param span: If true, calculate rows according to rowspans and colspans
            attributes. Otherwise ignore them.
        :param row: Return the specified row only. Zero-based index.
        :param column: Return the specified column only. Zero-based index.
        :param strip: strip data values

        Note: Due to the lots of complications that it may cause, this function
            won't look inside templates, parser functions, etc.
            See https://www.mediawiki.org/wiki/Extension:Pipe_Escape for how
            wiki-tables can be inserted within templates.


def cells(<EOL>self, row: int = None, column: int = None, span: bool = True,<EOL>) -> Union[List[List[Cell]], List[Cell], Cell]:

tbl_span = self._span<EOL>ss = tbl_span[<NUM_LIT:0>]<EOL>match_table = self._match_table<EOL>shadow = self._shadow<EOL>type_ = id(tbl_span)<EOL>type_to_spans = self._type_to_spans<EOL>spans = type_to_spans.setdefault(type_, [])<EOL>table_cells = []  <EOL>table_attrs = []  <EOL>attrs_match = None<EOL>for match_row in match_table:<EOL><INDENT>row_cells = []  <EOL>table_cells.append(row_cells)<EOL>header = match_row[<NUM_LIT:0>]['<STR_LIT>'] == '<STR_LIT:!>'<EOL>if span:<EOL><INDENT>row_attrs = []  <EOL>table_attrs.append(row_attrs)<EOL>row_attrs_append = row_attrs.append<EOL><DEDENT>for m in match_row:<EOL><INDENT>ms, me = m.span()<EOL>cell_span = [ss + ms, ss + me]<EOL>if span:<EOL><INDENT>s, e = m.span('<STR_LIT>')<EOL>attrs_match = ATTRS_MATCH(shadow[ms:me], s - ms, e - ms)<EOL>captures = attrs_match.captures<EOL>row_attrs_append(dict(zip(<EOL>captures('<STR_LIT>'), captures('<STR_LIT>')<EOL>)))<EOL><DEDENT>old_span = next((s for s in spans if s == cell_span), None)<EOL>if old_span is None:<EOL><INDENT>insort(spans, cell_span)<EOL><DEDENT>else:<EOL><INDENT>cell_span = old_span<EOL><DEDENT>row_cells.append(<EOL>Cell(<EOL>self._lststr,<EOL>header,<EOL>type_to_spans,<EOL>cell_span,<EOL>type_,<EOL>m,<EOL>attrs_match,<EOL>)<EOL>)<EOL><DEDENT><DEDENT>if table_cells and span:<EOL><INDENT>table_cells = _apply_attr_spans(table_attrs, table_cells)<EOL><DEDENT>if row is None:<EOL><INDENT>if column is None:<EOL><INDENT>return table_cells<EOL><DEDENT>return [r[column] for r in table_cells]<EOL><DEDENT>if column is None:<EOL><INDENT>return table_cells[row]<EOL><DEDENT>return table_cells[row][column]<EOL>

Return a list of lists containing Cell objects.

        :param span: If is True, rearrange the result according to colspan and
            rospan attributes.
        :param row: Return the specified row only. Zero-based index.
        :param column: Return the specified column only. Zero-based index.

        If both row and column are provided, return the relevant cell object.

        If only need the values inside cells, then use the ``data`` method
        instead.


@property<EOL><INDENT>def caption(self) -> Optional[str]:<DEDENT>

m = CAPTION_MATCH(self.string)<EOL>if m:<EOL><INDENT>return m['<STR_LIT>']<EOL><DEDENT>return None<EOL>


@caption.setter<EOL><INDENT>def caption(self, newcaption: str) -> None:<DEDENT>

m = CAPTION_MATCH(self.string)<EOL>if m:<EOL><INDENT>preattrs = m['<STR_LIT>']<EOL>attrs = m['<STR_LIT>'] or '<STR_LIT>'<EOL>oldcaption = m['<STR_LIT>']<EOL>self[len(preattrs + attrs):len(preattrs + attrs + oldcaption)] =newcaption<EOL><DEDENT>else:<EOL><INDENT>string = self.string<EOL>h, s, t = string.partition('<STR_LIT:\n>')<EOL>self.insert(len(h + s), '<STR_LIT>' + newcaption + '<STR_LIT:\n>')<EOL><DEDENT>


@property<EOL><INDENT>def caption_attrs(self) -> Optional[str]:<DEDENT>


@caption_attrs.setter<EOL><INDENT>def caption_attrs(self, attrs: str) -> None:<DEDENT>

string = self.string<EOL>h, s, t = string.partition('<STR_LIT:\n>')<EOL>m = CAPTION_MATCH(string)<EOL>if not m:<EOL><INDENT>self.insert(len(h + s), '<STR_LIT>' + attrs + '<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>preattrs = m['<STR_LIT>']<EOL>oldattrs = m['<STR_LIT>'] or '<STR_LIT>'<EOL>self[len(preattrs):len(preattrs + oldattrs)] = attrs<EOL><DEDENT>


@property<EOL><INDENT>def arguments(self) -> List[Argument]:<DEDENT>

shadow = self._shadow<EOL>split_spans = self._args_matcher(shadow).spans('<STR_LIT>')<EOL>if not split_spans:<EOL><INDENT>return []<EOL><DEDENT>arguments = []<EOL>arguments_append = arguments.append<EOL>type_to_spans = self._type_to_spans<EOL>ss, se = span = self._span<EOL>type_ = id(span)<EOL>lststr = self._lststr<EOL>string = lststr[<NUM_LIT:0>]<EOL>arg_spans = type_to_spans.setdefault(type_, [])<EOL>span_tuple_to_span_get = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in arg_spans}.get<EOL>for arg_self_start, arg_self_end in split_spans:<EOL><INDENT>s, e = arg_span = [ss + arg_self_start, ss + arg_self_end]<EOL>old_span = span_tuple_to_span_get((s, e))<EOL>if old_span is None:<EOL><INDENT>insort(arg_spans, arg_span)<EOL><DEDENT>else:<EOL><INDENT>arg_span = old_span<EOL><DEDENT>arg = Argument(lststr, type_to_spans, arg_span, type_)<EOL>arg._shadow_cache = (<EOL>string[s:e], shadow[arg_self_start:arg_self_end])<EOL>arguments_append(arg)<EOL><DEDENT>return arguments<EOL>

Parse template content. Create self.name and self.arguments.


def lists(self, pattern: str = None) -> List[WikiList]:

return [<EOL>lst for arg in self.arguments for lst in arg.lists(pattern) if lst]<EOL>

Return the lists in all arguments.

        For performance reasons it is usually preferred to get a specific
        Argument and use the `lists` method of that argument instead.


@property<EOL><INDENT>def name(self) -> str:<DEDENT>

h = self._atomic_partition(self._first_arg_sep)[<NUM_LIT:0>]<EOL>if len(h) == len(self.string):<EOL><INDENT>return h[<NUM_LIT:2>:-<NUM_LIT:2>]<EOL><DEDENT>return h[<NUM_LIT:2>:]<EOL>

Return template's name (includes whitespace).


@name.setter<EOL><INDENT>def name(self, newname: str) -> None:<DEDENT>

self[<NUM_LIT:2>:<NUM_LIT:2> + len(self.name)] = newname<EOL>


def __init__(<EOL>self,<EOL>string: Union[MutableSequence[str], str],<EOL>_type_to_spans: Dict[str, List[List[int]]] = None,<EOL>) -> None:

if _type_to_spans is not None:<EOL><INDENT>self._type_to_spans = _type_to_spans<EOL>self._lststr = string  <EOL>return<EOL><DEDENT>self._lststr = [string]<EOL>span = self._span = [<NUM_LIT:0>, len(string)]<EOL>byte_array = bytearray(string, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>_type = self._type<EOL>if _type not in SPAN_PARSER_TYPES:<EOL><INDENT>type_to_spans = self._type_to_spans = parse_to_spans(byte_array)<EOL>type_to_spans[_type] = [span]<EOL>self._shadow_cache = string, byte_array<EOL><DEDENT>else:<EOL><INDENT>head = byte_array[:<NUM_LIT:2>]<EOL>tail = byte_array[-<NUM_LIT:2>:]<EOL>byte_array[-<NUM_LIT:2>:] = byte_array[:<NUM_LIT:2>] = b'<STR_LIT>'<EOL>type_to_spans = parse_to_spans(byte_array)<EOL>self._shadow_cache = string, byte_array<EOL>type_to_spans[_type].insert(<NUM_LIT:0>, span)<EOL>self._type_to_spans = type_to_spans<EOL>byte_array[:<NUM_LIT:2>] = head<EOL>byte_array[-<NUM_LIT:2>:] = tail<EOL><DEDENT>

Initialize the object.

        Set the initial values for self._lststr, self._type_to_spans.

        :param string: The string to be parsed or a list containing the string
            of the parent object.
        :param _type_to_spans: If the lststr is already parsed, pass its
            _type_to_spans property as _type_to_spans to avoid parsing it
            again.


return self.string<EOL>


return '<STR_LIT>'.format(type(self).__name__, repr(self.string))<EOL>

Return the string representation of self.


def __contains__(self, value: Union[str, '<STR_LIT>']) -> bool:

<EOL>if isinstance(value, str):<EOL><INDENT>return value in self.string<EOL><DEDENT>if self._lststr is not value._lststr:<EOL><INDENT>return False<EOL><DEDENT>ps, pe = value._span<EOL>ss, se = self._span<EOL>if ss <= ps and se >= pe:<EOL><INDENT>return True<EOL><DEDENT>return False<EOL>

Return True if parsed_wikitext is inside self. False otherwise.

        Also self and parsed_wikitext should belong to the same parsed
        wikitext object for this function to return True.


def __getitem__(self, key: Union[slice, int]) -> str:

return self.string[key]<EOL>


def _check_index(self, key: Union[slice, int]) -> (int, int):

ss, se = self._span<EOL>if isinstance(key, int):<EOL><INDENT>if key < <NUM_LIT:0>:<EOL><INDENT>key += se - ss<EOL>if key < <NUM_LIT:0>:<EOL><INDENT>raise IndexError('<STR_LIT>')<EOL><DEDENT><DEDENT>elif key >= se - ss:<EOL><INDENT>raise IndexError('<STR_LIT>')<EOL><DEDENT>start = ss + key<EOL>return start, start + <NUM_LIT:1><EOL><DEDENT>if key.step is not None:<EOL><INDENT>raise NotImplementedError(<EOL>'<STR_LIT>')<EOL><DEDENT>start, stop = key.start or <NUM_LIT:0>, key.stop<EOL>if start < <NUM_LIT:0>:<EOL><INDENT>start += se - ss<EOL>if start < <NUM_LIT:0>:<EOL><INDENT>raise IndexError('<STR_LIT>')<EOL><DEDENT><DEDENT>if stop is None:<EOL><INDENT>stop = se - ss<EOL><DEDENT>elif stop < <NUM_LIT:0>:<EOL><INDENT>stop += se - ss<EOL><DEDENT>if start > stop:<EOL><INDENT>raise IndexError(<EOL>'<STR_LIT>')<EOL><DEDENT>return start + ss, stop + ss<EOL>

Return adjusted start and stop index as tuple.

        Used in  __setitem__ and __delitem__.


def __setitem__(<EOL>self,<EOL>key: Union[slice, int],<EOL>value: str,<EOL>) -> None:

start, stop = self._check_index(key)<EOL>lststr = self._lststr<EOL>lststr0 = lststr[<NUM_LIT:0>]<EOL>lststr[<NUM_LIT:0>] = lststr0[:start] + value + lststr0[stop:]<EOL>self._close_subspans(start, stop)<EOL>len_change = len(value) + start - stop<EOL>if len_change > <NUM_LIT:0>:<EOL><INDENT>self._insert_update(start, len_change)<EOL><DEDENT>elif len_change < <NUM_LIT:0>:<EOL><INDENT>self._shrink_update(<EOL>rmstart=stop + len_change,  <EOL>rmstop=stop)  <EOL><DEDENT>type_to_spans = self._type_to_spans<EOL>for type_, spans in parse_to_spans(<EOL>bytearray(value, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>).items():<EOL><INDENT>for s, e in spans:<EOL><INDENT>insort(type_to_spans[type_], [s + start, e + start])<EOL><DEDENT><DEDENT>

Set a new string for the given slice or character index.

        Use this method instead of calling `insert` and `del` consecutively.
        By doing so only one of the `_insert_update` and
        `_shrink_update` functions will be called and the performance
        will improve.


def __delitem__(self, key: Union[slice, int]) -> None:

start, stop = self._check_index(key)<EOL>lststr = self._lststr<EOL>lststr0 = lststr[<NUM_LIT:0>]<EOL>lststr[<NUM_LIT:0>] = lststr0[:start] + lststr0[stop:]<EOL>self._shrink_update(start, stop)<EOL>

Remove the specified range or character from self.string.

        Note: If an operation involves both insertion and deletion, it'll be
        safer to use the `insert` function first. Otherwise there is a
        possibility of insertion into the wrong spans.


def insert(self, index: int, string: str) -> None:

ss, se = self._span<EOL>lststr = self._lststr<EOL>lststr0 = lststr[<NUM_LIT:0>]<EOL>if index < <NUM_LIT:0>:<EOL><INDENT>index += se - ss<EOL>if index < <NUM_LIT:0>:<EOL><INDENT>index = <NUM_LIT:0><EOL><DEDENT><DEDENT>elif index > se - ss:  <EOL><INDENT>index = se - ss<EOL><DEDENT>index += ss<EOL>lststr[<NUM_LIT:0>] = lststr0[:index] + string + lststr0[index:]<EOL>string_len = len(string)<EOL>self._insert_update(<EOL>index=index,<EOL>length=string_len)<EOL>type_to_spans = self._type_to_spans<EOL>for type_, spans in parse_to_spans(<EOL>bytearray(string, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>).items():<EOL><INDENT>for s, e in spans:<EOL><INDENT>insort(type_to_spans[type_], [index + s, index + e])<EOL><DEDENT><DEDENT>

Insert the given string before the specified index.

        This method has the same effect as ``self[index:index] = string``;
        it only avoids some condition checks as it rules out the possibility
        of the key being an slice, or the need to shrink any of the sub-spans.

        If parse is False, don't parse the inserted string.


@property<EOL><INDENT>def span(self) -> tuple:<DEDENT>

return tuple(self._span)<EOL>

Return the span of self relative to the start of the root node.


@property<EOL><INDENT>def string(self) -> str:<DEDENT>

start, end = self._span<EOL>return self._lststr[<NUM_LIT:0>][start:end]<EOL>


@string.setter<EOL><INDENT>def string(self, newstring: str) -> None:<DEDENT>

self[:] = newstring<EOL>

Set a new string for this object. Note the old data will be lost.


@string.deleter<EOL><INDENT>def string(self) -> None:<DEDENT>

del self[:]<EOL>


def _atomic_partition(self, char: int) -> Tuple[str, str, str]:

s, e = self._span<EOL>index = self._shadow.find(char)<EOL>if index == -<NUM_LIT:1>:<EOL><INDENT>return self._lststr[<NUM_LIT:0>][s:e], '<STR_LIT>', '<STR_LIT>'<EOL><DEDENT>lststr0 = self._lststr[<NUM_LIT:0>]<EOL>return lststr0[s:s + index], chr(char), lststr0[s + index + <NUM_LIT:1>:e]<EOL>

Partition self.string where `char`'s not in atomic sub-spans.


def _subspans(self, type_: str) -> List[List[int]]:

return self._type_to_spans[type_]<EOL>

Return all the sub-span including self._span.


def _close_subspans(self, start: int, stop: int) -> None:

ss, se = self._span<EOL>for spans in self._type_to_spans.values():<EOL><INDENT>b = bisect(spans, [start])<EOL>for i, (s, e) in enumerate(spans[b:bisect(spans, [stop], b)]):<EOL><INDENT>if e <= stop:<EOL><INDENT>if ss != s or se != e:<EOL><INDENT>spans.pop(i + b)[:] = -<NUM_LIT:1>, -<NUM_LIT:1><EOL>b -= <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT><DEDENT>


def _shrink_update(self, rmstart: int, rmstop: int) -> None:

<EOL>for spans in self._type_to_spans.values():<EOL><INDENT>i = len(spans) - <NUM_LIT:1><EOL>while i >= <NUM_LIT:0>:<EOL><INDENT>s, e = span = spans[i]<EOL>if rmstop <= s:<EOL><INDENT>rmlength = rmstop - rmstart<EOL>span[:] = s - rmlength, e - rmlength<EOL>i -= <NUM_LIT:1><EOL>continue<EOL><DEDENT>break<EOL><DEDENT>else:<EOL><INDENT>continue<EOL><DEDENT>while True:<EOL><INDENT>if rmstart <= s:<EOL><INDENT>if rmstop < e:<EOL><INDENT>span[:] = rmstart, e + rmstart - rmstop<EOL>i -= <NUM_LIT:1><EOL>if i < <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>s, e = span = spans[i]<EOL>continue<EOL><DEDENT>spans.pop(i)[:] = -<NUM_LIT:1>, -<NUM_LIT:1><EOL>i -= <NUM_LIT:1><EOL>if i < <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>s, e = span = spans[i]<EOL>continue<EOL><DEDENT>break<EOL><DEDENT>while i >= <NUM_LIT:0>:<EOL><INDENT>if e <= rmstart:<EOL><INDENT>i -= <NUM_LIT:1><EOL>if i < <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>s, e = span = spans[i]<EOL>continue<EOL><DEDENT>span[<NUM_LIT:1>] -= rmstop - rmstart<EOL>i -= <NUM_LIT:1><EOL>if i < <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>s, e = span = spans[i]<EOL>continue<EOL><DEDENT><DEDENT>

Update self._type_to_spans according to the removed span.

        Warning: If an operation involves both _shrink_update and
        _insert_update, you might wanna consider doing the
        _insert_update before the _shrink_update as this function
        can cause data loss in self._type_to_spans.


def _insert_update(self, index: int, length: int) -> None:

ss, se = self._span<EOL>for spans in self._type_to_spans.values():<EOL><INDENT>for span in spans:<EOL><INDENT>if index < span[<NUM_LIT:1>] or span[<NUM_LIT:1>] == index == se:<EOL><INDENT>span[<NUM_LIT:1>] += length<EOL>if index < span[<NUM_LIT:0>] or span[<NUM_LIT:0>] == index != ss:<EOL><INDENT>span[<NUM_LIT:0>] += length<EOL><DEDENT><DEDENT><DEDENT><DEDENT>

Update self._type_to_spans according to the added length.


@property<EOL><INDENT>def nesting_level(self) -> int:<DEDENT>

ss, se = self._span<EOL>level = <NUM_LIT:0><EOL>type_to_spans = self._type_to_spans<EOL>for type_ in ('<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>spans = type_to_spans[type_]<EOL>for s, e in spans[:bisect(spans, [ss + <NUM_LIT:1>])]:<EOL><INDENT>if se <= e:<EOL><INDENT>level += <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT>return level<EOL>

Return the nesting level of self.

        The minimum nesting_level is 0. Being part of any Template or
        ParserFunction increases the level by one.


@property<EOL><INDENT>def _shadow(self) -> bytearray:<DEDENT>

ss, se = self._span<EOL>string = self._lststr[<NUM_LIT:0>][ss:se]<EOL>cached_string, shadow = getattr(<EOL>self, '<STR_LIT>', (None, None))<EOL>if cached_string == string:<EOL><INDENT>return shadow<EOL><DEDENT>shadow = bytearray(string, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>if self._type in SPAN_PARSER_TYPES:<EOL><INDENT>head = shadow[:<NUM_LIT:2>]<EOL>tail = shadow[-<NUM_LIT:2>:]<EOL>shadow[:<NUM_LIT:2>] = shadow[-<NUM_LIT:2>:] = b'<STR_LIT>'<EOL>parse_to_spans(shadow)<EOL>shadow[:<NUM_LIT:2>] = head<EOL>shadow[-<NUM_LIT:2>:] = tail<EOL><DEDENT>else:<EOL><INDENT>parse_to_spans(shadow)<EOL><DEDENT>self._shadow_cache = string, shadow<EOL>return shadow<EOL>

Return a copy of self.string with specific sub-spans replaced.

        Comments blocks are replaced by spaces. Other sub-spans are replaced
        by underscores.

        The replaced sub-spans are: (
            'Template', 'WikiLink', 'ParserFunction', 'ExtensionTag',
            'Comment',
        )

        This function is called upon extracting tables or extracting the data
        inside them.


ss, se = self._span<EOL>string = self._lststr[<NUM_LIT:0>][ss:se]<EOL>byte_array = bytearray(string, '<STR_LIT:ascii>', '<STR_LIT:replace>')<EOL>subspans = self._subspans<EOL>for type_ in '<STR_LIT>', '<STR_LIT>', '<STR_LIT>':<EOL><INDENT>for s, e in subspans(type_):<EOL><INDENT>byte_array[s:e] = b'<STR_LIT:U+0020>' + INVALID_EXT_CHARS_SUB(<EOL>b'<STR_LIT:U+0020>', byte_array[s + <NUM_LIT:2>:e - <NUM_LIT:2>]) + b'<STR_LIT:U+0020>'<EOL><DEDENT><DEDENT>for s, e in subspans('<STR_LIT>'):<EOL><INDENT>byte_array[s:e] = (e - s) * b'<STR_LIT:_>'<EOL><DEDENT>return byte_array<EOL>

Replace the invalid chars of SPAN_PARSER_TYPES with b'_'.

        For comments, all characters are replaced, but for ('Template',
        'ParserFunction', 'Parameter') only invalid characters are replaced.


def _pp_type_to_spans(self) -> Dict[str, List[List[int]]]:

ss, se = self._span<EOL>if ss == <NUM_LIT:0> and se == len(self._lststr[<NUM_LIT:0>]):<EOL><INDENT>return deepcopy(self._type_to_spans)<EOL><DEDENT>return {<EOL>type_: [<EOL>[s - ss, e - ss] for s, e in spans[bisect(spans, [ss]):]<EOL>if e <= se<EOL>] for type_, spans in self._type_to_spans.items()}<EOL>

Create the arguments for the parse function used in pformat method.

        Only return sub-spans and change the them to fit the new scope, i.e
        self.string.


def pprint(self, indent: str = '<STR_LIT:U+0020>', remove_comments=False):

warn(<EOL>'<STR_LIT>',<EOL>DeprecationWarning,<EOL>)<EOL>return self.pformat(indent, remove_comments)<EOL>


def pformat(self, indent: str = '<STR_LIT:U+0020>', remove_comments=False) -> str:

ws = WS<EOL>string = self.string<EOL>parsed = WikiText([string], self._pp_type_to_spans())<EOL>span = [<NUM_LIT:0>, len(string)]<EOL>parsed._span = span<EOL>parsed._type_to_spans['<STR_LIT>'] = [span]<EOL>if remove_comments:<EOL><INDENT>for c in parsed.comments:<EOL><INDENT>del c[:]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for c in parsed.comments:<EOL><INDENT>if not c.contents.strip(ws):<EOL><INDENT>del c[:]<EOL><DEDENT><DEDENT><DEDENT>for template in reversed(parsed.templates):<EOL><INDENT>stripped_tl_name = template.name.strip(ws)<EOL>template.name = (<EOL>'<STR_LIT:U+0020>' + stripped_tl_name + '<STR_LIT:U+0020>'<EOL>if stripped_tl_name[<NUM_LIT:0>] == '<STR_LIT:{>' else stripped_tl_name<EOL>)<EOL>args = template.arguments<EOL>if not args:<EOL><INDENT>continue<EOL><DEDENT>if '<STR_LIT::>' in stripped_tl_name:<EOL><INDENT>not_a_parser_function = None<EOL><DEDENT>else:<EOL><INDENT>not_a_parser_function = True<EOL><DEDENT>arg_stripped_names = [a.name.strip(ws) for a in args]<EOL>arg_positionalities = [a.positional for a in args]<EOL>arg_name_lengths = [<EOL>wcswidth(n.replace('<STR_LIT>', '<STR_LIT:?>'))<EOL>if not p else <NUM_LIT:0><EOL>for n, p in zip(arg_stripped_names, arg_positionalities)<EOL>]<EOL>max_name_len = max(arg_name_lengths)<EOL>level = template.nesting_level<EOL>newline_indent = '<STR_LIT:\n>' + indent * level<EOL>template.name += newline_indent<EOL>if level == <NUM_LIT:1>:<EOL><INDENT>last_comment_indent = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>last_comment_indent = '<STR_LIT>' + indent * (level - <NUM_LIT:2>) + '<STR_LIT>'<EOL><DEDENT>last_arg = args.pop()<EOL>last_is_positional = arg_positionalities.pop()<EOL>last_value = last_arg.value<EOL>last_stripped_value = last_value.strip(ws)<EOL>if last_is_positional and last_value != last_stripped_value:<EOL><INDENT>stop_conversion = True<EOL>if not last_value.endswith('<STR_LIT:\n>' + indent * (level - <NUM_LIT:1>)):<EOL><INDENT>last_arg.value = last_value + last_comment_indent<EOL><DEDENT><DEDENT>elif not_a_parser_function:<EOL><INDENT>stop_conversion = False<EOL>last_arg.name = (<EOL>'<STR_LIT:U+0020>' + arg_stripped_names.pop() + '<STR_LIT:U+0020>' +<EOL>'<STR_LIT:U+0020>' * (max_name_len - arg_name_lengths.pop()))<EOL>last_arg.value = (<EOL>'<STR_LIT:U+0020>' + last_stripped_value + '<STR_LIT:\n>' + indent * (level - <NUM_LIT:1>))<EOL><DEDENT>elif last_is_positional:<EOL><INDENT>stop_conversion = True<EOL>last_arg.value = last_value + last_comment_indent<EOL><DEDENT>else:<EOL><INDENT>stop_conversion = True<EOL>last_arg.name = '<STR_LIT:U+0020>' + last_arg.name.lstrip(ws)<EOL>if not last_value.endswith('<STR_LIT:\n>' + indent * (level - <NUM_LIT:1>)):<EOL><INDENT>last_arg.value = (<EOL>last_value.rstrip(ws) + '<STR_LIT:U+0020>' + last_comment_indent)<EOL><DEDENT><DEDENT>if not args:<EOL><INDENT>continue<EOL><DEDENT>comment_indent = '<STR_LIT>' + indent * (level - <NUM_LIT:1>) + '<STR_LIT>'<EOL>for arg, stripped_name, positional, arg_name_len in zip(<EOL>reversed(args),<EOL>reversed(arg_stripped_names),<EOL>reversed(arg_positionalities),<EOL>reversed(arg_name_lengths),<EOL>):<EOL><INDENT>value = arg.value<EOL>stripped_value = value.strip(ws)<EOL>if stop_conversion:<EOL><INDENT>if not value.endswith(newline_indent):<EOL><INDENT>arg.value += comment_indent<EOL><DEDENT><DEDENT>elif positional and value != stripped_value:<EOL><INDENT>stop_conversion = True<EOL>if not value.endswith(newline_indent):<EOL><INDENT>arg.value += comment_indent<EOL><DEDENT><DEDENT>elif not_a_parser_function:<EOL><INDENT>arg.name = (<EOL>'<STR_LIT:U+0020>' + stripped_name + '<STR_LIT:U+0020>' +<EOL>'<STR_LIT:U+0020>' * (max_name_len - arg_name_len))<EOL>arg.value = '<STR_LIT:U+0020>' + stripped_value + newline_indent<EOL><DEDENT><DEDENT><DEDENT>i = <NUM_LIT:0><EOL>functions = parsed.parser_functions<EOL>while i < len(functions):<EOL><INDENT>func = functions[i]<EOL>i += <NUM_LIT:1><EOL>name = func.name<EOL>ls_name = name.lstrip(ws)<EOL>lws = len(name) - len(ls_name)<EOL>if lws:<EOL><INDENT>del func[<NUM_LIT:2>:lws + <NUM_LIT:2>]<EOL><DEDENT>if ls_name.lower() in ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>continue<EOL><DEDENT>args = func.arguments<EOL>level = func.nesting_level<EOL>short_indent = '<STR_LIT:\n>' + indent * (level - <NUM_LIT:1>)<EOL>newline_indent = short_indent + indent<EOL>if len(args) == <NUM_LIT:1>:<EOL><INDENT>arg = args[<NUM_LIT:0>]<EOL>if arg.positional:<EOL><INDENT>arg.value = (<EOL>newline_indent + arg.value.strip(ws) + short_indent)<EOL><DEDENT>else:<EOL><INDENT>arg.name = newline_indent + arg.name.lstrip(ws)<EOL>arg.value = arg.value.rstrip(ws) + short_indent<EOL><DEDENT>functions = parsed.parser_functions<EOL>continue<EOL><DEDENT>arg = args[<NUM_LIT:0>]<EOL>if arg.positional:<EOL><INDENT>arg.value =newline_indent + arg.value.strip(ws) + newline_indent<EOL><DEDENT>else:<EOL><INDENT>arg.name = newline_indent + arg.name.lstrip(ws)<EOL>arg.value = arg.value.rstrip(ws) + newline_indent<EOL><DEDENT>for arg in args[<NUM_LIT:1>:-<NUM_LIT:1>]:<EOL><INDENT>if arg.positional:<EOL><INDENT>arg.value = '<STR_LIT:U+0020>' + arg.value.strip(ws) + newline_indent<EOL><DEDENT>else:<EOL><INDENT>arg.name = '<STR_LIT:U+0020>' + arg.name.lstrip(ws)<EOL>arg.value = arg.value.rstrip(ws) + newline_indent<EOL><DEDENT><DEDENT>arg = args[-<NUM_LIT:1>]<EOL>if arg.positional:<EOL><INDENT>arg.value = '<STR_LIT:U+0020>' + arg.value.strip(ws) + short_indent<EOL><DEDENT>else:<EOL><INDENT>arg.name = '<STR_LIT:U+0020>' + arg.name.lstrip(ws)<EOL>arg.value = arg.value.rstrip(ws) + short_indent<EOL><DEDENT>functions = parsed.parser_functions<EOL><DEDENT>return parsed.string<EOL>

Return a pretty-print of self.string as string.

        Try to organize templates and parser functions by indenting, aligning
        at the equal signs, and adding space where appropriate.

        Note that this function will not mutate self.


@property<EOL><INDENT>def parameters(self) -> List['<STR_LIT>']:<DEDENT>

_lststr = self._lststr<EOL>_type_to_spans = self._type_to_spans<EOL>return [<EOL>Parameter(_lststr, _type_to_spans, span, '<STR_LIT>')<EOL>for span in self._subspans('<STR_LIT>')]<EOL>


@property<EOL><INDENT>def parser_functions(self) -> List['<STR_LIT>']:<DEDENT>

_lststr = self._lststr<EOL>_type_to_spans = self._type_to_spans<EOL>return [<EOL>ParserFunction(_lststr, _type_to_spans, span, '<STR_LIT>')<EOL>for span in self._subspans('<STR_LIT>')]<EOL>

Return a list of parser function objects.


@property<EOL><INDENT>def templates(self) -> List['<STR_LIT>']:<DEDENT>

_lststr = self._lststr<EOL>_type_to_spans = self._type_to_spans<EOL>return [<EOL>Template(_lststr, _type_to_spans, span, '<STR_LIT>')<EOL>for span in self._subspans('<STR_LIT>')]<EOL>

Return a list of templates as template objects.


@property<EOL><INDENT>def wikilinks(self) -> List['<STR_LIT>']:<DEDENT>

_lststr = self._lststr<EOL>_type_to_spans = self._type_to_spans<EOL>return [<EOL>WikiLink(_lststr, _type_to_spans, span, '<STR_LIT>')<EOL>for span in self._subspans('<STR_LIT>')]<EOL>


@property<EOL><INDENT>def comments(self) -> List['<STR_LIT>']:<DEDENT>

_lststr = self._lststr<EOL>_type_to_spans = self._type_to_spans<EOL>return [<EOL>Comment(_lststr, _type_to_spans, span, '<STR_LIT>')<EOL>for span in self._subspans('<STR_LIT>')]<EOL>


@property<EOL><INDENT>def external_links(self) -> List['<STR_LIT>']:<DEDENT>

external_links = []  <EOL>external_links_append = external_links.append<EOL>type_to_spans = self._type_to_spans<EOL>lststr = self._lststr<EOL>ss, se = self._span<EOL>spans = type_to_spans.setdefault('<STR_LIT>', [])<EOL>if not spans:<EOL><INDENT>spans_append = spans.append<EOL>for m in EXTERNAL_LINK_FINDITER(self._ext_link_shadow):<EOL><INDENT>s, e = m.span()<EOL>span = [ss + s, ss + e]<EOL>spans_append(span)<EOL>external_links_append(<EOL>ExternalLink(lststr, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT>return external_links<EOL><DEDENT>span_tuple_to_span_get = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in spans}.get<EOL>for m in EXTERNAL_LINK_FINDITER(self._ext_link_shadow):<EOL><INDENT>s, e = m.span()<EOL>span = s, e = [s + ss, e + ss]<EOL>old_span = span_tuple_to_span_get((s, e))<EOL>if old_span is None:<EOL><INDENT>insort(spans, span)<EOL><DEDENT>else:<EOL><INDENT>span = old_span<EOL><DEDENT>external_links_append(<EOL>ExternalLink(lststr, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT>return external_links<EOL>

Return a list of found external link objects.

        Note:
            Templates adjacent to external links are considered part of the
            link. In reality, this depends on the contents of the template:

            >>> WikiText(
            ...    'http://example.com{{dead link}}'
            ...).external_links[0].url
            'http://example.com{{dead link}}'

            >>> WikiText(
            ...    '[http://example.com{{space template}} text]'
            ...).external_links[0].url
            'http://example.com{{space template}}'


@property<EOL><INDENT>def sections(self) -> List['<STR_LIT>']:<DEDENT>

sections = []  <EOL>sections_append = sections.append<EOL>type_to_spans = self._type_to_spans<EOL>lststr = self._lststr<EOL>ss, se = _span = self._span<EOL>type_spans = type_to_spans.setdefault('<STR_LIT>', [])<EOL>full_match = SECTIONS_FULLMATCH(self._shadow)<EOL>section_spans = full_match.spans('<STR_LIT>')<EOL>levels = [len(eq) for eq in full_match.captures('<STR_LIT>')]<EOL>if not type_spans:<EOL><INDENT>spans_append = type_spans.append<EOL>for current_index, (current_level, (s, e)) in enumerate(<EOL>zip(levels, section_spans), <NUM_LIT:1><EOL>):<EOL><INDENT>for section_index, section_level in enumerate(<EOL>levels[current_index:], current_index<EOL>):<EOL><INDENT>if current_level and section_level > current_level:<EOL><INDENT>e = section_spans[section_index][<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>span = [ss + s, ss + e]<EOL>spans_append(span)<EOL>sections_append(<EOL>Section(lststr, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT>return sections<EOL><DEDENT>span_tuple_to_span = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in type_spans}.get<EOL>for current_index, (current_level, (s, e)) in enumerate(<EOL>zip(levels, section_spans), <NUM_LIT:1><EOL>):<EOL><INDENT>for section_index, section_level in enumerate(<EOL>levels[current_index:], current_index<EOL>):<EOL><INDENT>if current_level and section_level > current_level:<EOL><INDENT>e = section_spans[section_index][<NUM_LIT:1>]<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>s, e = ss + s, ss + e<EOL>old_span = span_tuple_to_span((s, e))<EOL>if old_span is None:<EOL><INDENT>span = [s, e]<EOL>insort(type_spans, span)<EOL><DEDENT>else:<EOL><INDENT>span = old_span<EOL><DEDENT>sections_append(Section(lststr, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT>return sections<EOL>

Return a list of section in current wikitext.

        The first section will always be the lead section, even if it is an
        empty string.


@property<EOL><INDENT>def tables(self) -> List['<STR_LIT>']:<DEDENT>

tables = []  <EOL>tables_append = tables.append<EOL>type_to_spans = self._type_to_spans<EOL>lststr = self._lststr<EOL>shadow = self._shadow[:]<EOL>ss, se = self._span<EOL>spans = type_to_spans.setdefault('<STR_LIT>', [])<EOL>if not spans:<EOL><INDENT>m = True  <EOL>while m:<EOL><INDENT>m = False<EOL>for m in TABLE_FINDITER(shadow):<EOL><INDENT>ms, me = m.span()<EOL>span = [ss + ms + len(m[<NUM_LIT:1>]), ss + me]<EOL>spans.append(span)<EOL>tables_append(Table(lststr, type_to_spans, span, '<STR_LIT>'))<EOL>shadow[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL><DEDENT><DEDENT>return tables<EOL><DEDENT>span_tuple_to_span_get = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in spans}.get<EOL>m = True<EOL>while m:<EOL><INDENT>m = False<EOL>for m in TABLE_FINDITER(shadow):<EOL><INDENT>ms, me = m.span()<EOL>s, e = ss + ms + len(m[<NUM_LIT:1>]), ss + me<EOL>old_span = span_tuple_to_span_get((s, e))<EOL>if old_span is None:<EOL><INDENT>span = [s, e]<EOL>insort(spans, span)<EOL><DEDENT>else:<EOL><INDENT>span = old_span<EOL><DEDENT>tables_append(Table(lststr, type_to_spans, span, '<STR_LIT>'))<EOL>shadow[ms:me] = b'<STR_LIT:_>' * (me - ms)<EOL><DEDENT><DEDENT>return tables<EOL>


@property<EOL><INDENT>def _lists_shadow_ss(self) -> Tuple[bytearray, int]:<DEDENT>

return self._shadow, self._span[<NUM_LIT:0>]<EOL>

Return appropriate shadow and its offset to be used by `lists`.


def lists(self, pattern: str = None) -> List['<STR_LIT>']:

lists = []<EOL>lists_append = lists.append<EOL>lststr = self._lststr<EOL>type_to_spans = self._type_to_spans<EOL>spans = type_to_spans.setdefault('<STR_LIT>', [])<EOL>span_tuple_to_span_get = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in spans}.get<EOL>shadow, ss = self._lists_shadow_ss<EOL>for pattern in(r'<STR_LIT>', r'<STR_LIT>', '<STR_LIT>') if pattern is None else (pattern,):<EOL><INDENT>for m in finditer(<EOL>LIST_PATTERN_FORMAT.replace(b'<STR_LIT>', pattern.encode()),<EOL>shadow, MULTILINE<EOL>):<EOL><INDENT>ms, me = m.span()<EOL>s, e = ss + ms, ss + me<EOL>old_span = span_tuple_to_span_get((s, e))<EOL>if old_span is None:<EOL><INDENT>span = [s, e]<EOL>insort(spans, span)<EOL><DEDENT>else:<EOL><INDENT>span = old_span<EOL><DEDENT>lists_append(WikiList(<EOL>lststr, pattern, m, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT><DEDENT>return lists<EOL>

r"""Return a list of WikiList objects.

        :param pattern: The starting pattern for list items.
            Return all types of lists (ol, ul, and dl) if pattern is None.
            If pattern is not None, it will be passed to the regex engine,
            remember to escape the `*` character. Examples:

                - `\#` means top-level ordered lists
                - `\#\*` means unordred lists inside an ordered one
                - Currently definition lists are not well supported, but you
                    can use `[:;]` as their pattern.

            Tips and tricks:

                Be careful when using the following patterns as they will
                probably cause malfunction in the `sublists` method of the
                resultant List. (However don't worry about them if you are
                not going to use the `sublists` method.)

                - Use `\*+` as a pattern and nested unordered lists will be
                    treated as flat.
                - Use `\*\s*` as pattern to rtstrip `items` of the list.

                Although the pattern parameter is optional, but specifying it
                can improve the performance.


def tags(self, name=None) -> List['<STR_LIT>']:

lststr = self._lststr<EOL>type_to_spans = self._type_to_spans<EOL>if name:<EOL><INDENT>if name in _tag_extensions:<EOL><INDENT>string = lststr[<NUM_LIT:0>]<EOL>return [<EOL>Tag(lststr, type_to_spans, span, '<STR_LIT>')<EOL>for span in type_to_spans['<STR_LIT>']<EOL>if string.startswith('<STR_LIT:<>' + name, span[<NUM_LIT:0>])]<EOL><DEDENT>tags = []  <EOL><DEDENT>else:<EOL><INDENT>tags = [<EOL>Tag(lststr, type_to_spans, span, '<STR_LIT>')<EOL>for span in type_to_spans['<STR_LIT>']]<EOL><DEDENT>tags_append = tags.append<EOL>ss = self._span[<NUM_LIT:0>]<EOL>shadow = self._shadow<EOL>if name:<EOL><INDENT>reversed_start_matches = reversed([m for m in regex_compile(<EOL>START_TAG_PATTERN.replace(<EOL>rb'<STR_LIT>', rb'<STR_LIT>' + name.encode() + rb'<STR_LIT:)>')<EOL>).finditer(shadow)])<EOL>end_search = regex_compile(END_TAG_PATTERN .replace(<EOL>b'<STR_LIT>', name.encode())).search<EOL><DEDENT>else:<EOL><INDENT>reversed_start_matches = reversed(<EOL>[m for m in START_TAG_FINDITER(shadow)])<EOL><DEDENT>shadow_copy = shadow[:]<EOL>spans = type_to_spans.setdefault('<STR_LIT>', [])<EOL>span_tuple_to_span_get = {(s[<NUM_LIT:0>], s[<NUM_LIT:1>]): s for s in spans}.get<EOL>spans_append = spans.append<EOL>for start_match in reversed_start_matches:<EOL><INDENT>if start_match['<STR_LIT>']:<EOL><INDENT>s, e = start_match.span()<EOL>span = [ss + s, ss + e]<EOL><DEDENT>else:<EOL><INDENT>if name:<EOL><INDENT>end_match = end_search(shadow_copy, start_match.end())<EOL><DEDENT>else:<EOL><INDENT>end_match = search(<EOL>END_TAG_PATTERN.replace(<EOL>b'<STR_LIT>', start_match['<STR_LIT:name>']),<EOL>shadow_copy)<EOL><DEDENT>if end_match:<EOL><INDENT>s, e = end_match.span()<EOL>shadow_copy[s:e] = b'<STR_LIT:_>' * (e - s)<EOL>span = [ss + start_match.start(), ss + e]<EOL><DEDENT>else:<EOL><INDENT>s, e = start_match.span()<EOL>span = [ss + s, ss + e]<EOL><DEDENT><DEDENT>old_span = span_tuple_to_span_get((span[<NUM_LIT:0>], span[<NUM_LIT:1>]))<EOL>if old_span is None:<EOL><INDENT>spans_append(span)<EOL><DEDENT>else:<EOL><INDENT>span = old_span<EOL><DEDENT>tags_append(Tag(lststr, type_to_spans, span, '<STR_LIT>'))<EOL><DEDENT>return sorted(tags, key=attrgetter('<STR_LIT>'))<EOL>


@staticmethod<EOL><INDENT>def parent(type_: Optional[str] = None) -> None:<DEDENT>

return None<EOL>

Return None (The parent of the root node is None).


@staticmethod<EOL><INDENT>def ancestors(type_: Optional[str] = None) -> list:<DEDENT>

return []<EOL>

Return [] (the root node has no ancestors).


def __init__(<EOL>self,<EOL>string: Union[str, MutableSequence[str]],<EOL>_type_to_spans: Optional[Dict[str, List[List[int]]]] = None,<EOL>_span: Optional[List[int]] = None,<EOL>_type: Optional[Union[str, int]] = None,<EOL>) -> None:

if _type is None:<EOL><INDENT>self._type = _type = type(self).__name__<EOL>super().__init__(string)<EOL>if _type not in SPAN_PARSER_TYPES:<EOL><INDENT>span = [<NUM_LIT:0>, len(string)]<EOL>self._type_to_spans[_type] = [span]<EOL>self._span = span<EOL><DEDENT><DEDENT>else:<EOL><INDENT>self._type = _type<EOL>super().__init__(string, _type_to_spans)<EOL>self._span = _span<EOL><DEDENT>


def _subspans(self, _type: str) -> Generator[int, None, None]:

ss, se = self._span<EOL>spans = self._type_to_spans[_type]<EOL>b = bisect(spans, [ss])<EOL>for span in spans[b:bisect(spans, [se], b)]:<EOL><INDENT>if span[<NUM_LIT:1>] <= se:<EOL><INDENT>yield span<EOL><DEDENT><DEDENT>

Yield all the sub-span indices excluding self._span.


def ancestors(self, type_: Optional[str] = None) -> List['<STR_LIT>']:

if type_ is None:<EOL><INDENT>types = SPAN_PARSER_TYPES<EOL><DEDENT>else:<EOL><INDENT>types = type_,<EOL><DEDENT>lststr = self._lststr<EOL>type_to_spans = self._type_to_spans<EOL>ss, se = self._span<EOL>ancestors = []<EOL>ancestors_append = ancestors.append<EOL>for type_ in types:<EOL><INDENT>cls = globals()[type_]<EOL>spans = type_to_spans[type_]<EOL>for span in spans[:bisect(spans, [ss])]:<EOL><INDENT>if se < span[<NUM_LIT:1>]:<EOL><INDENT>ancestors_append(cls(lststr, type_to_spans, span, type_))<EOL><DEDENT><DEDENT><DEDENT>return sorted(ancestors, key=lambda i: ss - i._span[<NUM_LIT:0>])<EOL>

Return the ancestors of the current node.

        :param type_: the type of the desired ancestors as a string.
            Currently the following types are supported: {Template,
            ParserFunction, WikiLink, Comment, Parameter, ExtensionTag}.
            The default is None and means all the ancestors of any type above.