pythonimmediate.lowlevel module

class pythonimmediate.lowlevel.PTTBalancedTokenList(data: 'BalancedTokenList')[source]

Bases: PyToTeXData

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PTTBlock(data: 'str')[source]

Bases: PyToTeXData

static coerce(s: str) PTTBlock[source]

Construct a block from arbitrary string, delete some content if needed.

static ignore_last_space(s: str) PTTBlock[source]

Construct a block from arbitrary string, deleting trailing spaces on each line.

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PTTInt(data: 'int')[source]

Bases: PyToTeXData

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PTTTeXLine(data: str)[source]

Bases: PyToTeXData

Represents a line to be tokenized in TeX’s current catcode regime. The trailing newline is not included, i.e. it’s tokenized under \endlinechar=-1.

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PTTVerbatimLine(data: 'str')[source]

Bases: PyToTeXData

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PTTVerbatimRawLine(data: bytes)[source]

Bases: PyToTeXData

Represents a line to be tokenized verbatim. Internally the \readline primitive is used, as such, any trailing spaces are stripped. The trailing newline is not included, i.e. it’s read under \endlinechar=-1.

read_code() str
serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PyToTeXData[source]

Bases: ABC

Internal class (for now). Represent a data type that can be sent from Python to \(\TeX\).

abstract static read_code(var: str) str[source]

Takes an argument, the variable name (with backslash prefixed such as "\abc".)

Returns

some \(\TeX\) code that when executed in expl3 category code regime, will read a value of the specified data type and assign it to the variable.

abstract serialize() bytes[source]

Return a bytes object that can be passed to engine.write() directly.

class pythonimmediate.lowlevel.PythonCallTeXFunctionType(*args, **kwargs)[source]

Bases: Protocol

class pythonimmediate.lowlevel.PythonCallTeXSyncFunctionType(*args, **kwargs)[source]

Bases: PythonCallTeXFunctionType, Protocol

class pythonimmediate.lowlevel.Python_call_TeX_data(TeX_code: 'str', recursive: 'bool', finish: 'bool', sync: 'Optional[bool]')[source]

Bases: object

class pythonimmediate.lowlevel.Python_call_TeX_extra(ptt_argtypes: 'Tuple[Type[PyToTeXData], ...]', ttp_argtypes: 'Union[Type[TeXToPyData], Tuple[Type[TeXToPyData], ...]]')[source]

Bases: object

pythonimmediate.lowlevel.Python_call_TeX_local(TeX_code: str, *, recursive: bool = True, sync: Optional[bool] = None, finish: bool = False) Callable[source]

Internal function. See scan_Python_call_TeX().

class pythonimmediate.lowlevel.TTPBlock[source]

Bases: TeXToPyData, str

static read() TTPBlock[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

send_code() str
send_code_var() str
class pythonimmediate.lowlevel.TTPEBlock[source]

Bases: TeXToPyData, str

A kind of argument that interprets “escaped string” and fully expand anything inside. For example, {\\} sends a single backslash to Python, {\{} sends a single { to Python.

Done by fully expand the argument in \escapechar=-1 and convert it to a string. Additional precaution is needed, see the note above (TODO write documentation).

Refer to Note on argument expansion of estr-type functions for more details.

static read() TTPEBlock[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

send_code() str
send_code_var() str
class pythonimmediate.lowlevel.TTPELine[source]

Bases: TeXToPyData, str

Same as TTPEBlock, but for a single line only.

static read() TTPELine[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

send_code() str
send_code_var() str
class pythonimmediate.lowlevel.TTPEmbeddedLine[source]

Bases: TeXToPyData, str

static read() TTPEmbeddedLine[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

static send_code(arg: str) str[source]

Return some \(\TeX\) code that sends the argument to Python, where arg represents a token list or equivalent (such as #1).

static send_code_var(arg: str) str[source]

Return some \(\TeX\) code that sends the argument to Python, where var represents a token list variable (such as \l__my_var_tl) that contains the content to be sent.

class pythonimmediate.lowlevel.TTPLine[source]

Bases: TeXToPyData, str

static read() TTPLine[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

send_code() str
send_code_var() str
class pythonimmediate.lowlevel.TTPRawLine[source]

Bases: TeXToPyData, bytes

static read() TTPRawLine[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

send_code() str
send_code_var() str
class pythonimmediate.lowlevel.TeXToPyData[source]

Bases: ABC

Internal class (for now). Represent a data type that can be sent from \(\TeX\) to Python.

abstract static read() TeXToPyData[source]

Given that \(\TeX\) has just sent the data, read into a Python object.

abstract static send_code(arg: str) str[source]

Return some \(\TeX\) code that sends the argument to Python, where arg represents a token list or equivalent (such as #1).

abstract static send_code_var(var: str) str[source]

Return some \(\TeX\) code that sends the argument to Python, where var represents a token list variable (such as \l__my_var_tl) that contains the content to be sent.

pythonimmediate.lowlevel.bootstrap_code_functions: list[Callable[[Engine], str]]

Internal constant. Contains functions that takes an engine object and returns some code before substitute_private() is applied on it.

pythonimmediate.lowlevel.build_Python_call_TeX(T: Type, TeX_code: str, *, recursive: bool = True, sync: Optional[bool] = None, finish: bool = False) None[source]

Internal function. See scan_Python_call_TeX().

T has the form Callable[[T1, T2], Tuple[U1, U2]] where the Tx are subclasses of PyToTeXData and the Ux are subclasses of TeXToPyData

The Tuple[…] can optionally be a single type, then it is almost equivalent to a tuple of one element It can also be None

pythonimmediate.lowlevel.can_be_mangled_to(original: str, mangled: str) bool[source]

Internal functions, used to implemented pycode() environment.

If original is put in a \(\TeX\) file, read in other catcode regime (possibly drop trailing spaces/tabs), and then sent through \write (possibly convert control characters to ^^-notation), is it possible that the written content is equal to mangled?

The function is somewhat tolerant (might return True in some cases where False should be returned), but not too tolerant.

Example:

>>> can_be_mangled_to("a\n", "a\n")
True
>>> can_be_mangled_to("\n", "\n")
True
>>> can_be_mangled_to("\t\n", "\n")
True
>>> can_be_mangled_to("\t\n", "\t\n")
True
>>> can_be_mangled_to("\t\n", "^^I\n")
True
>>> can_be_mangled_to("\ta\n", "^^Ia\n")
True
>>> can_be_mangled_to("a b\n", "a b\n")
True
>>> can_be_mangled_to("a b  \n", "a b\n")
True
>>> can_be_mangled_to("a\n", "b\n")
False
pythonimmediate.lowlevel.check_line(line: str, *, braces: bool, newline: bool, continue_: Optional[bool]) None[source]

check user-provided line before sending to TeX for execution

pythonimmediate.lowlevel.define_Python_call_TeX(TeX_code: str, ptt_argtypes: List[Type[PyToTeXData]], ttp_argtypes: List[Type[TeXToPyData]], *, recursive: bool = True, sync: Optional[bool] = None, finish: bool = False) Tuple[Callable[[Engine], str], PythonCallTeXFunctionType][source]

Internal function.

TeX_code should be some expl3 code that defines a function with name %name% that when called should:

  • run some \(\TeX\)-code (which includes reading the arguments, if any)

  • do the following if sync: * send r to Python (equivalently write %sync%) * send whatever needed for the output (as in ttp_argtypes)

  • call \pythonimmediatelisten iff not finish.

This is allowed to contain the following:

  • %name%: the name of the function to be defined as explained above.

  • %read_arg0(var_name)%, %read_arg1(…)%: will be expanded to code that reads the input.

  • %send_arg0(…)%, %send_arg1(…)%: will be expanded to code that sends the content.

  • %send_arg0_var(var_name)%, %send_arg1_var(…)%: will be expanded to code that sends the content in the variable.

  • %optional_sync%: expanded to code that writes r (to sync), if sync is True.

  • %naive_flush% and %naive_inline%: as explained in mark_bootstrap_naive_replace(). (although usually you don’t need to explicitly write this, it’s embedded in the send*() command of the last argument, or %sync%)

Parameters
  • ptt_argtypes – list of argument types to be sent from Python to TeX (i.e. input of the TeX function)

  • ttp_argtypes – list of argument types to be sent from TeX to Python (i.e. output of the TeX function)

  • recursive – whether the TeX_code might call another Python function. Default to True. It does not hurt to always specify True, but performance would be a bit slower.

  • sync – whether the Python function need to wait for the TeX function to finish. Required if ttp_argtypes is not empty. This should be left to be the default None most of the time. (which will make it always sync if debugging, otherwise only sync if needed i.e. there’s some output)

  • finish – Include this if and only if \pythonimmediatelisten is omitted. Normally this is not needed, but it can be used as a slight optimization; and it’s needed internally to implement run_none_finish among others. For each TeX-call-Python layer, emph{exactly one} finish call can be made. If the function itself doesn’t call any finish call (which happens most of the time), then the wrapper will call run_none_finish.

Returns

some TeX code to be executed, and a Python function object that when called will call the TeX function on the passed-in TeX engine and return the result.

Note that the TeX_code must eventually be executed on the corresponding engine for the program to work correctly.

Possible optimizations:

  • the r is not needed if not recursive and ttp_argtypes is nonempty (the output itself tells Python when the \(\TeX\)-code finished)

  • the first line of the output may be on the same line as the r itself (done, use TTPEmbeddedLine type, although a bit hacky)

pythonimmediate.lowlevel.define_TeX_call_Python(f: Callable[[...], None], name: Optional[str] = None, argtypes: Optional[List[Type[TeXToPyData]]] = None, identifier: Optional[str] = None) Callable[[Engine], str][source]

This function setups some internal data structure, and returns the \(\TeX\)-code to be executed on the \(\TeX\)-side to define the macro.

Parameters
  • f – the Python function to be executed. It should take some arguments plus a keyword argument engine and eventually (optionally) call one of the _finish functions.

  • name – the macro name on the \(\TeX\)-side. This should only consist of letter characters in expl3 catcode regime.

  • argtypes – list of argument types. If it’s None it will be automatically deduced from the function f’s signature.

  • identifier – should be obtained by get_random_Python_identifier().

Returns

some code (to be executed in expl3 catcode regime) as explained above.

pythonimmediate.lowlevel.define_internal_handler(f: FunctionType) FunctionType[source]

Define a TeX function with TeX name = f.__name__ that calls f().

This does not define the specified function in any particular engine, just add them to the bootstrap_code.

pythonimmediate.lowlevel.get_bootstrap_code(engine: Engine) str[source]

Return the bootstrap code for an engine.

This is before the call to substitute_private().

pythonimmediate.lowlevel.mark_bootstrap_naive_replace(code: str) None[source]

Similar to mark_bootstrap(), but code may contain one of the following:

  • %naive_inline: replaced with ^^J \__naive_flush_data:

    if Engine.config.naive_flush is True, else become empty

  • %naive_flush%: replaced with \__send_content:e {\__naive_flush_data:}

    if Engine.config.naive_flush is True

pythonimmediate.lowlevel.run_error_finish(full_error: PTTBlock, short_error: PTTBlock) None[source]

Internal function.

run_error_finish is fatal to \(\TeX\), so we only run it when it’s fatal to Python.

We want to make sure the Python traceback is printed strictly before run_error_finish() is called, so that the Python traceback is not interleaved with \(\TeX\) error messages.

pythonimmediate.lowlevel.scan_Python_call_TeX(sourcecode: str, filename: Optional[str] = None) None[source]

Internal function.

Scan the file in filename for occurrences of typing.cast(T, Python_call_TeX_local(...)), then call build_Python_call_TeX(T, ...) for each occurrence.

The way the whole thing work is:

  • In the Python code, some typing.cast(T, Python_call_TeX_local(...)) are used.

  • This function is called on all the library source codes to scan for those occurrences, build necessary data structures for the Python_call_TeX_local() function calls to work correctly.

  • When Python_call_TeX_local() is actually called, it does some magic to return the correct function.

Done this way, the type checking works correctly and it’s not necessary to define global temporary variables.

Don’t use this function on untrusted code.

pythonimmediate.lowlevel.scan_Python_call_TeX_module(name: str) None[source]

Internal function. Can be used as scan_Python_call_TeX_module(__name__) to scan the current module.