Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
JelteF authored Jul 23, 2024
2 parents eba40f1 + 92d394b commit 955abb9
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 33 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ include *.md
recursive-include pylatex *.py
recursive-include python2_source/pylatex *.py
include versioneer.py
include examples/kitten.jpg
16 changes: 8 additions & 8 deletions pylatex/base_classes/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@ def __init__(
>>> options=Options('12pt', 'a4paper', 'twoside'),
>>> arguments='article').dumps()
'\\documentclass[12pt,a4paper,twoside]{article}'
>>> Command('com')
>>> Command('com').dumps()
'\\com'
>>> Command('com', 'first')
>>> Command('com', 'first').dumps()
'\\com{first}'
>>> Command('com', 'first', 'option')
>>> Command('com', 'first', 'option').dumps()
'\\com[option]{first}'
>>> Command('com', 'first', 'option', 'second')
>>> Command('com', 'first', 'option', extra_arguments='second').dumps()
'\\com{first}[option]{second}'
"""
Expand Down Expand Up @@ -326,10 +326,10 @@ class Options(Parameters):
Examples
--------
>>> args = Options('a', 'b', 'c').dumps()
>>> Options('a', 'b', 'c').dumps()
'[a,b,c]'
>>> Options('clip', width=50, height='25em', trim='1 2 3 4').dumps()
'[clip,trim=1 2 3 4,width=50,height=25em]'
'[clip,width=50,height=25em,trim=1 2 3 4]'
"""

Expand Down Expand Up @@ -367,9 +367,9 @@ class Arguments(Parameters):
Examples
--------
>>> args = Arguments('a', 'b', 'c').dumps()
>>> Arguments('a', 'b', 'c').dumps()
'{a}{b}{c}'
>>> args = Arguments('clip', width=50, height='25em').dumps()
>>> args = Arguments('clip', width=50, height='25em')
>>> args.dumps()
'{clip}{width=50}{height=25em}'
Expand Down
8 changes: 7 additions & 1 deletion pylatex/base_classes/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
.. :copyright: (c) 2014 by Jelte Fennema.
:license: MIT, see License for more details.
"""
from __future__ import annotations

from collections import UserList
from contextlib import contextmanager
from typing import TypeVar
from collections.abc import Generator

from pylatex.utils import dumps_list

Expand Down Expand Up @@ -95,7 +98,7 @@ def dumps_packages(self):
return super().dumps_packages()

@contextmanager
def create(self, child):
def create(self, child: T) -> Generator[T, None, None]:
"""Add a LaTeX object to current container, context-manager style.
Args
Expand All @@ -113,6 +116,9 @@ def create(self, child):
self.append(child)


T = TypeVar("T", bound=Container)


class Environment(Container):
r"""A base class for LaTeX environments.
Expand Down
41 changes: 41 additions & 0 deletions pylatex/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,47 @@ class Document(Environment):
For instance, if you need to use ``\maketitle`` you can add the title,
author and date commands to the preamble to make it work.
Example
-------
>>> import pylatex
>>> import pathlib
>>> import tempfile
>>> # Create a place where we can write our PDF to disk
>>> temp_output_path = pathlib.Path(tempfile.mkdtemp())
>>> temp_output_path.mkdir(exist_ok=True)
>>> document_fpath = temp_output_path / 'my_document.pdf'
>>> # The Document class is the main point of interaction.
>>> doc = pylatex.Document(
>>> document_fpath.with_suffix(''), # give the output file path without the .pdf
>>> inputenc=None,
>>> page_numbers=False,
>>> indent=False,
>>> fontenc=None,
>>> lmodern=True,
>>> textcomp=False,
>>> documentclass='article',
>>> geometry_options='paperheight=0.4in,paperwidth=1in,margin=0.1in',
>>> )
>>> # Append content to the document, which can be plain text, or
>>> # object from pylatex. For now lets just say hello!
>>> doc.append('Hello World')
>>> # Inspect the generated latex
>>> print(doc.dumps())
\documentclass{article}%
\usepackage{lmodern}%
\usepackage{parskip}%
\usepackage{geometry}%
\geometry{paperheight=0.4in,paperwidth=1in,margin=0.1in}%
%
%
%
\begin{document}%
\pagestyle{empty}%
\normalsize%
Hello World%
\end{document}
>>> # Generate and the PDF in document_fpath
>>> doc.generate_pdf()
"""

def __init__(
Expand Down
6 changes: 3 additions & 3 deletions pylatex/quantities.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,20 @@ def __init__(self, quantity, *, options=None, format_cb=None):
>>> speed = 3.14159265 * pq.meter / pq.second
>>> Quantity(speed, options={'round-precision': 3,
... 'round-mode': 'figures'}).dumps()
'\\SI[round-mode=figures,round-precision=3]{3.14159265}{\meter\per\second}'
'\\SI[round-precision=3,round-mode=figures]{3.14159265}{\\meter\\per\\second}'
Uncertainties are also handled:
>>> length = pq.UncertainQuantity(16.0, pq.meter, 0.3)
>>> width = pq.UncertainQuantity(16.0, pq.meter, 0.4)
>>> Quantity(length*width).dumps()
'\\SI{256.0 +- 0.5}{\meter\tothe{2}}
'\\SI{256.0 +- 8.0}{\\meter\\tothe{2}}'
Ordinary numbers are also supported:
>>> Avogadro_constant = 6.022140857e23
>>> Quantity(Avogadro_constant, options={'round-precision': 3}).dumps()
'\\num[round-precision=3]{6.022e23}'
'\\num[round-precision=3]{6.022140857e+23}'
"""
import numpy as np
Expand Down
9 changes: 8 additions & 1 deletion pylatex/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,14 @@ def add_row(self, *cells, color=None, escape=None, mapper=None, strict=True):
escape = self.escape

# Propagate packages used in cells
for c in cells:
def flatten(x):
if _is_iterable(x):
return [a for i in x for a in flatten(i)]
else:
return [x]

flat_list = [c for c in cells] + flatten(cells)
for c in flat_list:
if isinstance(c, LatexObject):
for p in c.packages:
self.packages.add(p)
Expand Down
33 changes: 18 additions & 15 deletions pylatex/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ def escape_latex(s):
Examples
--------
>>> escape_latex("Total cost: $30,000")
'Total cost: \$30,000'
NoEscape(Total cost: \$30,000)
>>> escape_latex("Issue #5 occurs in 30% of all cases")
'Issue \#5 occurs in 30\% of all cases'
NoEscape(Issue \#5 occurs in 30\% of all cases)
>>> print(escape_latex("Total cost: $30,000"))
Total cost: \$30,000
References
----------
Expand Down Expand Up @@ -126,7 +127,8 @@ def fix_filename(path):
>>> fix_filename("/etc/local/foo.bar.baz/document.pdf")
'/etc/local/foo.bar.baz/document.pdf'
>>> fix_filename("/etc/local/foo.bar.baz/foo~1/document.pdf")
'\detokenize{/etc/local/foo.bar.baz/foo~1/document.pdf}'
'\\detokenize{/etc/local/foo.bar.baz/foo~1/document.pdf}'
"""

path_parts = path.split("/" if os.name == "posix" else "\\")
Expand Down Expand Up @@ -174,16 +176,17 @@ def dumps_list(l, *, escape=True, token="%\n", mapper=None, as_content=True):
Examples
--------
>>> dumps_list([r"\textbf{Test}", r"\nth{4}"])
'\\textbf{Test}%\n\\nth{4}'
NoEscape(\textbackslash{}textbf\{Test\}%
\textbackslash{}nth\{4\})
>>> print(dumps_list([r"\textbf{Test}", r"\nth{4}"]))
\textbf{Test}
\nth{4}
\textbackslash{}textbf\{Test\}%
\textbackslash{}nth\{4\}
>>> print(pylatex.utils.dumps_list(["There are", 4, "lights!"]))
There are
4
There are%
4%
lights!
>>> print(dumps_list(["$100%", "True"], escape=True))
\$100\%
\$100\%%
True
"""
strings = (
Expand Down Expand Up @@ -254,7 +257,7 @@ def bold(s, *, escape=True):
Examples
--------
>>> bold("hello")
'\\textbf{hello}'
NoEscape(\textbf{hello})
>>> print(bold("hello"))
\textbf{hello}
"""
Expand Down Expand Up @@ -285,7 +288,7 @@ def italic(s, *, escape=True):
Examples
--------
>>> italic("hello")
'\\textit{hello}'
NoEscape(\textit{hello})
>>> print(italic("hello"))
\textit{hello}
"""
Expand Down Expand Up @@ -315,10 +318,10 @@ def verbatim(s, *, delimiter="|"):
Examples
--------
>>> verbatim(r"\renewcommand{}")
'\\verb|\\renewcommand{}|'
NoEscape(\verb|\renewcommand{}|)
>>> print(verbatim(r"\renewcommand{}"))
\verb|\renewcommand{}|
>>> print(verbatim('pi|pe', '!'))
>>> print(verbatim('pi|pe', delimiter='!'))
\verb!pi|pe!
"""

Expand All @@ -335,8 +338,8 @@ def make_temp_dir():
Examples
--------
>>> make_temp_dir()
'/var/folders/g9/ct5f3_r52c37rbls5_9nc_qc0000gn/T/pylatex'
>>> make_temp_dir() # xdoctest: +IGNORE_WANT
'/tmp/pylatex-tmp.y_b7xp21'
"""

global _tmp_path
Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ skip = ['.bzr', '.direnv', '.eggs', '.git', '.hg', '.mypy_cache', '.nox', '.pant

[tool.black]
extend-exclude = 'versioneer\.py|src'

[tool.pytest.ini_options]
addopts = "--xdoctest --ignore-glob=setup.py --ignore-glob=docs"
norecursedirs = ".git __pycache__ docs"
filterwarnings = [
"default",
]
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"matrices": ["numpy"],
"matplotlib": ["matplotlib"],
"quantities": ["quantities", "numpy"],
"testing": ["pytest>=4.6", "coverage", "pytest-cov", "black", "isort"],
"testing": ["pytest>=4.6", "coverage", "pytest-cov", "black", "isort", "xdoctest"],
"packaging": ["twine"],
}

Expand Down
2 changes: 1 addition & 1 deletion testall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ else
fi

echo -e '\e[32mTesting tests directory\e[0m'
if ! $python "$(command -v pytest)" --cov=pylatex tests/*; then
if ! $python "$(command -v pytest)" --xdoctest --cov=pylatex pylatex tests/*.py; then
exit 1
fi
mv .coverage{,.tests}
Expand Down
4 changes: 2 additions & 2 deletions tests/test_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_math():
repr(vec)

# Numpy
m = np.matrix([[2, 3, 4], [0, 0, 1], [0, 0, 2]])
m = np.array([[2, 3, 4], [0, 0, 1], [0, 0, 2]])

matrix = Matrix(matrix=m, mtype="p", alignment=None)
repr(matrix)
Expand Down Expand Up @@ -210,7 +210,7 @@ def test_graphics():
# Subfigure
s = SubFigure(data=None, position=None, width=r"0.45\linewidth")

s.add_image(filename="", width="r\linewidth", placement=None)
s.add_image(filename="", width=r"r\linewidth", placement=None)

s.add_caption(caption="")
repr(s)
Expand Down
72 changes: 72 additions & 0 deletions tests/test_tabular.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python

from pylatex import Document, Section, Tabular, MultiColumn, StandAloneGraphic

# This file contains function that test several Tabular related functionality.


def test_tabular_can_add_row_passing_many_arguments(sample_logo_path):
"""
Test that Tabular can add a row as described in the function body:
The first method is to pass the content of each cell as a separate argument.
Returns
-------
None.
"""
doc = Document()

with doc.create(Section("Can Add Row Passing Many Arguments")):
with doc.create(Tabular("|c|c|", booktabs=True)) as table:

mc1 = MultiColumn(
1, align="l", data=StandAloneGraphic(filename=sample_logo_path)
)
mc2 = MultiColumn(
1, align="l", data=StandAloneGraphic(filename=sample_logo_path)
)

table.add_row(mc1, mc2)
doc.generate_pdf(clean_tex=False)


def test_tabular_can_add_row_passing_iterable(sample_logo_path):
"""
Test that Tabular can add a row as described in the function body:
The second method
is to pass a single argument that is an iterable that contains each
contents.
Returns
-------
None.
"""
doc = Document()

with doc.create(Section("Can Add Row Passing Iterable")):
with doc.create(Tabular("|c|c|", booktabs=True)) as table:
multi_columns_array = [
MultiColumn(
1, align="l", data=StandAloneGraphic(filename=sample_logo_path)
),
MultiColumn(
1, align="l", data=StandAloneGraphic(filename=sample_logo_path)
),
]

table.add_row(multi_columns_array)
doc.generate_pdf()


if __name__ == "__main__":

import os.path as osp

sample_logo_path = osp.abspath(
osp.join(__file__[0:-15], "..", "examples", "sample-logo.png")
)

test_tabular_can_add_row_passing_many_arguments(sample_logo_path=sample_logo_path)
test_tabular_can_add_row_passing_iterable(sample_logo_path=sample_logo_path)
2 changes: 1 addition & 1 deletion tests/test_utils_fix_filename.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ def test_dots_in_path_and_multiple_in_filename():
def test_tilde_in_filename():
fname = "/etc/local/foo.bar.baz/foo~1/document.pdf"
assert (
fix_filename(fname) == "\detokenize{/etc/local/foo.bar.baz/foo~1/document.pdf}"
fix_filename(fname) == r"\detokenize{/etc/local/foo.bar.baz/foo~1/document.pdf}"
)

0 comments on commit 955abb9

Please sign in to comment.