diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e8093a5..e3741703 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,37 @@ **Note**: This is the last version of *vpype* to support Python 3.7. New features and improvements: -* Updated the internal data model to support global and per-layer metadata (#359) +* Added support for global and per-layer metadata (#359) - This feature is intended as a generic mechanism whereby a set of properties may be attached to specific layers (layer property) or all of them (global property). Properties are identified by a name and may be of arbitrary type (e.g. integer, floating point, color, etc.). This new infrastructure is used by several of the features introduced in this release, paves the way for future features, and further empowers plug-in writers. See the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#metadata) for more background information on metadata. + This feature is intended as a generic mechanism whereby a set of properties may be attached to specific layers (layer property) or all of them (global property). Properties are identified by a name and may be of arbitrary type (e.g. integer, floating point, color, etc.). This new infrastructure is used by several of the features introduced in this release, paves the way for future features, and further empowers plug-in writers. See the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#properties) for more background information on metadata. * Layer color, pen width, and name are now customizable (#359, #376, #389) * The `read` commands now sets layer color, pen width, and name based on the input SVG if possible. * The new `color`, `penwdith`, and `name` commands can be used to modify layer color, pen width, and name. - * The new `pens` command can apply a predefined or custom scheme on multiple layers at once. Two schemes, `rgb` and `cmyk`, are included and others may be defined in the configuration file. + * The new `pens` command can apply a predefined or custom scheme on multiple layers at once. Two common schemes are built-in: `rgb` and `cmyk`. Custom schemes can be defined in the configuration file. * The `show` and `write` commands were updated to take into account these new layer properties. +* The `read` command now records the source SVG paths in the `vp_source` and `vp_sources` system properties (see the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#system-properties)) (#397) + +* Added property substitution to CLI user input (#395) + + The input provided to most commands' arguments and options may now contain substitution patterns which will be replaced by the corresponding property value. Property substitution patterns are marked with curly braces (e.g. `{property_name}`) and support the same formatting capabilities as the Python's [`format()` function](https://docs.python.org/3/library/string.html#formatstrings). For example, the following command draws the layer name and pen width: + ```bash + $ vpype read input.svg text --layer 1 "Name: {vp_name} Pen width: {vp_pen_width:.2f}" write output.svg + ``` + See the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#property-substitution) for more information and examples. + +* Added expression substitution to CLI user input (#397) + + The input provided to most command's arguments and option may now contain expression patterns which will be evaluated before the command is run. Expression patterns are marked with the percent `%` symbol (e.g. `%3+4%`) and support a large subset of the Python language. For example, the following pipeline adds a rectangular frame to a document with a given margin: + ```bash + $ vpype read my_file.svg \ + eval "%m = 1*cm%" \ + rect %m% %m% "%prop.vp_page_size[0]-2*m%" "%prop.vp_page_size[1]-2*m%" \ + write %basename(vp_filename)%_framed.svg + ``` + See the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#expression-substitution) for more information and examples. + * The `read` command can now optionally sort geometries by attributes (e.g. stroke color, stroke width, etc.) instead of by SVG layer (#378, #389) * The `read` and `write` commands now preserve a sub-set of SVG attributes (experimental) (#359, #389) @@ -29,20 +50,19 @@ New features and improvements: * `propdel`: deletes a given global or layer property * `propclear`: removes all global and/or layer properties -* Added property substitution to CLI user input (#395) - - The input provided to most commands' arguments and options may now contain substitution patterns which will be replaced by the corresponding property value. See the [documentation](https://vpype.readthedocs.io/en/latest/fundamentals.html#cli-property-substitution) for more information and examples. - * Updated layer operation commands to handle metadata (#359) * When a single source layer is specified and `--prob` is not used, the `lcopy` and `lmove` commands now copy the source layer's properties to the destination layer (possibly overwriting existing properties). * When `--prob` is not used, the `lswap` command now swaps the layer properties as well. * These behaviors can be disabled with the `--no-prop` option. -* Improved the handling of block processors (#395) - - Block processors are commands which, when combined with `begin` and `end`, operate on the sequence they encompass. For example, the sequence `begin grid 2 2 random end` creates a 2x2 grid of random line patches. The infrastructure underlying block processors has been overhauled to increase their usefulness and extensibility. - +* Improved block processors (#395, #397) + + * Simplified and improved the infrastructure underlying block processors for better extensibility. + * The `grid` block processor now adjusts the page size according to its layout. + * The `grid` and `repeat` block processors now sets variables for expressions in nested commands. + * Added `forfile` block processor to iterate over a list of file. + * Added `forlayer` block processor to iterate over the existing layers. * The `begin` marker is now optional and implied whenever a block processor command is encountered. The following pipelines are thus equivalent: ```bash $ vpype begin grid 2 2 random end show @@ -51,6 +71,8 @@ New features and improvements: *Note*: the `end` marker must always be used to mark the end of a block. * Commands inside the block now have access to the current layer structure and its metadata. This makes their use more predictable. For example, `begin grid 2 2 random --layer new end` now correctly generates patches of random lines on different layers. * The `grid` block processor now first iterate along lines instead of columns. + +* The `read` command now will ignore a missing file if `--no-fail` parameter is used (#397) * Changed the initial default target layer to 1 (#395) @@ -94,8 +116,8 @@ API changes: Block processor commands (decorated with `@block_processor`) are no longer sub-classes of `BlockProcessor` (which has been removed). The are instead regular functions (like commands of other types) which take a `State` instance and a list of processors as first arguments. -* Added methods to `vpype_cli.State` to support property substitution, deferred arguments/options evaluation and block processor implementations (#395) -* `vpype.Document` and `vpype.LineCollection` have additional members to manage properties through the `vpype._MetadataMixin` mix-in class (#359) +* Added methods to `vpype_cli.State` to support expression and property substitution, deferred arguments/options evaluation and block processor implementations (#395, #397) +* `vpype.Document` and `vpype.LineCollection` have multiple, non-breaking additions to support metadata (in particular through the `vpype._MetadataMixin` mix-in class) (#359, #397) * Renamed `vpype.Document.empty_copy()` to `vpype.Document.clone()` for coherence with `vpype.LineCollection` (the old name remains for backward compatibility) (#359, #380) * Added `vpype.read_svg_by_attribute()` to read SVG while sorting geometries by arbitrary attributes (#378) * Added an argument to `vpype_cli.execute()` to pass global option such as `--verbose` (#378) @@ -104,7 +126,7 @@ Other changes: * Renamed the bundled config file to `vpype_config.toml` (#359) * Changed dependencies to dataclasses (instead of attrs) and tomli (instead of toml) (#362) * Removed dependency to click-plugin (#388) -* Various documentation improvements (#359, #363) +* Improved documentation, in particular the [Fundamentals](https://vpype.readthedocs.io/en/latest/fundamentals.html) and [Cookbook](https://vpype.readthedocs.io/en/latest/cookbook.html) sections (#359, #363, #397) #### 1.8.1 (2022-01-13) diff --git a/README.md b/README.md index fbce445d..204b562e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![PyPI](https://img.shields.io/pypi/v/vpype?label=PyPI&logo=pypi)](https://pypi.org/project/vpype/) [![python](https://img.shields.io/github/languages/top/abey79/vpype)](https://www.python.org) [![Downloads](https://pepy.tech/badge/vpype)](https://pepy.tech/project/vpype) -[![license](https://img.shields.io/pypi/l/vpype)](https://vpype.readthedocs.io/en/stable/license.html) +[![license](https://img.shields.io/pypi/l/vpype)](https://vpype.readthedocs.io/en/latest/license.html) ![Test](https://img.shields.io/github/workflow/status/abey79/vpype/Lint%20and%20Tests?label=Tests&logo=github) [![codecov](https://codecov.io/gh/abey79/vpype/branch/master/graph/badge.svg?token=CE7FD9D6XO)](https://codecov.io/gh/abey79/vpype) [![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=abey79_vpype&metric=alert_status)](https://sonarcloud.io/dashboard?id=abey79_vpype) @@ -50,22 +50,22 @@ already exists for plotting [pixel art](https://github.com/abey79/vpype-pixelart [half-toning with hatches](https://github.com/abey79/hatched), and much more. See below for a [list of existing plug-ins](#plug-ins). -_vpype_ is also a [well documented](https://vpype.readthedocs.io/en/stable/api.html) **Python library** +_vpype_ is also a [well documented](https://vpype.readthedocs.io/en/latest/api.html) **Python library** useful to create generative art and tools for plotters. It includes data structures, utility and I/O functions, as well as a hardware-accelerated flexible viewer for vector graphics. For example, the plotter generative art environment [vsketch](https://github.com/abey79/vsketch) is built upon _vpype_. -Check the [documentation](https://vpype.readthedocs.io/en/stable/) for a more thorough introduction to _vpype_. +Check the [documentation](https://vpype.readthedocs.io/en/latest/) for a more thorough introduction to _vpype_. ## How does it work? _vpype_ works by building so-called _pipelines_ of _commands_, where each command's output is fed to the next command's input. -Some commands load geometries into the pipeline (e.g. the [`read`](https://vpype.readthedocs.io/en/stable/reference.html#read) +Some commands load geometries into the pipeline (e.g. the [`read`](https://vpype.readthedocs.io/en/latest/reference.html#read) command which loads geometries from a SVG file). Other commands modify these geometries, e.g. by cropping -them ([`crop`](https://vpype.readthedocs.io/en/stable/reference.html#crop)) or reordering them to minimize pen-up -travels ([`linesort`](https://vpype.readthedocs.io/en/stable/reference.html#linesort)). Finally, some other commands -just read the geometries in the pipeline for display purposes ([`show`](https://vpype.readthedocs.io/en/stable/reference.html#show)) -or output to file ([`write`](https://vpype.readthedocs.io/en/stable/reference.html#write)). +them ([`crop`](https://vpype.readthedocs.io/en/latest/reference.html#crop)) or reordering them to minimize pen-up +travels ([`linesort`](https://vpype.readthedocs.io/en/latest/reference.html#linesort)). Finally, some other commands +just read the geometries in the pipeline for display purposes ([`show`](https://vpype.readthedocs.io/en/latest/reference.html#show)) +or output to file ([`write`](https://vpype.readthedocs.io/en/latest/reference.html#write)). Pipeline are defined using the _vpype_'s CLI (command-line interface) in a terminal by typing `vpype` followed by the list of commands, each with their optional parameters and their arguments: @@ -73,63 +73,115 @@ list of commands, each with their optional parameters and their arguments: ![command line](https://github.com/abey79/vpype/raw/master/docs/images/command_line.svg) This pipeline uses five commands (in bold): -- [`read`](https://vpype.readthedocs.io/en/stable/reference.html#read) loads geometries from a SVG file. -- [`linemerge`](https://vpype.readthedocs.io/en/stable/reference.html#linemerge) merges paths whose extremities are close to each other (within the provided tolerance). -- [`linesort`](https://vpype.readthedocs.io/en/stable/reference.html#linesort) reorder paths such as to minimise the pen-up travel. -- [`crop`](https://vpype.readthedocs.io/en/stable/reference.html#crop), well, crops. -- [`write`](https://vpype.readthedocs.io/en/stable/reference.html#write) export the resulting geometries to a SVG file. +- [`read`](https://vpype.readthedocs.io/en/latest/reference.html#read) loads geometries from a SVG file. +- [`linemerge`](https://vpype.readthedocs.io/en/latest/reference.html#linemerge) merges paths whose extremities are close to each other (within the provided tolerance). +- [`linesort`](https://vpype.readthedocs.io/en/latest/reference.html#linesort) reorder paths such as to minimise the pen-up travel. +- [`crop`](https://vpype.readthedocs.io/en/latest/reference.html#crop), well, crops. +- [`write`](https://vpype.readthedocs.io/en/latest/reference.html#write) export the resulting geometries to a SVG file. There are many more commands available in *vpype*, see the [overview](#feature-overview) below. Some commands have arguments, which are always required (in italic). For example, a file path must be provided to the -[`read`](https://vpype.readthedocs.io/en/stable/reference.html#read) command and dimensions must be provided to the [`crop`](https://vpype.readthedocs.io/en/stable/reference.html#crop) commands. A command may also have options which are, well, -optional. In this example, `--page-size a4` means that the [`write`](https://vpype.readthedocs.io/en/stable/reference.html#write) command will generate a A4-sized SVG (otherwise it -would have the same size as _in.svg_). Likewise, because `--center` is used, the [`write`](https://vpype.readthedocs.io/en/stable/reference.html#write) command will center geometries +[`read`](https://vpype.readthedocs.io/en/latest/reference.html#read) command and dimensions must be provided to the [`crop`](https://vpype.readthedocs.io/en/latest/reference.html#crop) commands. A command may also have options which are, well, +optional. In this example, `--page-size a4` means that the [`write`](https://vpype.readthedocs.io/en/latest/reference.html#write) command will generate a A4-sized SVG (otherwise it +would have the same size as _in.svg_). Likewise, because `--center` is used, the [`write`](https://vpype.readthedocs.io/en/latest/reference.html#write) command will center geometries on the page before saving the SVG (otherwise the geometries would have been left at their original location). ## Examples -**Note**: although it is not required, commands are separated by multiple spaces for clarity in the following examples. +**Note**: The following examples are laid out over multiple lines using end-of-line escaping (`\`). This is done to highlight the various commands of which the pipeline is made and would typically not be done in real-world use. Load an SVG file, scale it to a specific size, and export it centered on an A4-sized, ready-to-plot SVG file: -``` -vpype read input.svg scaleto 10cm 10cm write --page-size a4 --center output.svg +```bash +$ vpype \ + read input.svg \ + layout --fit-to-margins 2cm a4 \ + write output.svg ``` -Optimize paths to reduce plotting time (merge connected lines and sort them to minimize pen-up distance): -``` -vpype read input.svg linemerge --tolerance 0.1mm linesort write output.svg +Optimize paths to reduce plotting time (merge connected lines, sort them to minimize pen-up distance, randomize closed paths' seam, and reduce the number of nodes): +```bash +$ vpype \ + read input.svg \ + linemerge --tolerance 0.1mm \ + linesort \ + reloop \ + linesimplify \ + write output.svg ``` -Visualize the path structure of large SVG files, showing whether lines are properly joined or not thanks to a colorful -display: -``` -vpype read input.svg show --colorful +Load a SVG and display it in *vpype*'s viewer, which enable close inspection of the layer and path structure): +```bash +$ vpype \ + read input.svg \ + show ``` Load several SVG files and save them as a single, multi-layer SVG file (e.g. for multicolored drawings): +```bash +$ vpype \ + forfile "*.svg" \ + read --layer %_i% %_path% \ + end \ + write output.svg ``` -vpype read -l 1 input1.svg read -l 2 input2.svg write output.svg + +Export a SVG to HPGL for vintage plotters: +```bash +$ vpype \ + read input.svg \ + layout --fit-to-margins 2cm --landscape a4 \ + write --device hp7475a output.hpgl ``` -Create arbitrarily-sized, grid-like designs like this page's top banner: +Draw the layer name on a SVG (this example uses [property substitution](https://vpype.readthedocs.io/en/latest/fundamentals.html#property-substitution)): +```bash +$ vpype \ + read input.svg \ + text --layer 1 "{vp_name}" \ + write output.svg ``` -vpype begin grid -o 1cm 1cm 10 13 script alien_letter.py scaleto 0.5cm 0.5cm end show + +Merge multiple SVG files in a grid layout (this example uses [expression substitution](https://vpype.readthedocs.io/en/latest/fundamentals.html#expression-substitution)): +```bash +$ vpype \ + eval "files=glob('*.svg')" \ + eval "cols=3; rows=ceil(len(files)/cols)" \ + grid -o 10cm 10cm "%cols%" "%rows%" \ + read --no-fail "%files[_i] if _i < len(files) else ''%" \ + layout -m 0.5cm 10x10cm \ + end \ + write combined_on_a_grid.svg ``` -Export to HPGL for vintage plotters: +An interactive version of the previous example is available in `examples/grid.vpy`. It makes use of `input()` expressions to ask parameters from the user: +```bash +$ vpype -I examples/grid.vpy +Files [*.svg]? +Number of columns [3]? 4 +Column width [10cm]? +Row height [10cm]? 15cm +Margin [0.5cm]? +Output path [output.svg]? ``` -vpype read input.svg write --device hp7475a --page-size a4 --landscape --center output.hpgl + +Split a SVG into one file per layer: +```bash +$ vpype \ + read input.svg \ + forlayer \ + write "output_%_name or _lid%.svg" \ + end ``` + +More examples and recipes are available in the [cookbook](https://vpype.readthedocs.io/en/latest/cookbook.html). ## What _vpype_ isn't? _vpype_ caters to plotter generative art and does not aim to be a general purpose (think Illustrator/InkScape) vector graphic tools. One of the main reason for this is the fact _vpype_ converts everything -curvy (circles, bezier curves, etc.) to lines made of small segments. _vpype_ also dismisses the stroke and fill -properties (color, line width, etc.) of the imported graphics. These design choices make possible _vpype_'s rich feature -set, but makes its use for, e.g., printed media limited. +curvy (circles, bezier curves, etc.) to lines made of small segments. _vpype_ does import metadata such stroke and fill color, stroke width, etc., it only makes partial use of them and does not aim to maintain a full consistency with the SVG specification. These design choices make _vpype_'s rich feature set possible, but limits its use for, e.g., printed media. ## Installation @@ -148,7 +200,7 @@ when using this installation method). ```bash pip install vpype ``` - This version does not include the [`show`](https://vpype.readthedocs.io/en/stable/reference.html#show) command but does not require some of the dependencies which are more difficult or impossible to install on some platforms (such as matplotlib, PySide2, and ModernGL). + This version does not include the [`show`](https://vpype.readthedocs.io/en/latest/reference.html#show) command but does not require some of the dependencies which are more difficult or impossible to install on some platforms (such as matplotlib, PySide2, and ModernGL). ## Documentation @@ -160,7 +212,7 @@ vpype --help # general help and command list vpype COMMAND --help # help for a specific command ``` -In addition, the [online documentation](https://vpype.readthedocs.io/en/stable/) provides extensive background +In addition, the [online documentation](https://vpype.readthedocs.io/en/latest/) provides extensive background information on the fundamentals behind _vpype_, a cookbook covering most common tasks, the _vpype_ API documentation, and much more. @@ -169,66 +221,70 @@ and much more. #### General -- Easy to use **CLI** interface with integrated help (`vpype --help`and `vpype COMMAND --help`) and support for arbitrary units (e.g. `vpype read input.svg translate 3cm 2in`). -- First-class **multi-layer support** with global or per-layer processing (e.g. `vpype COMMANDNAME --layer 1,3`) and optionally-probabilistic layer edition commands ([`lmove`](https://vpype.readthedocs.io/en/stable/reference.html#lmove), [`lcopy`](https://vpype.readthedocs.io/en/stable/reference.html#lcopy), [`ldelete`](https://vpype.readthedocs.io/en/stable/reference.html#ldelete), [`lswap`](https://vpype.readthedocs.io/en/stable/reference.html#lswap), [`lreverse`](https://vpype.readthedocs.io/en/stable/reference.html#lreverse)). -- Powerful hardware-accelerated **display** command with adjustable units, optional per-line coloring, optional pen-up trajectories display and per-layer visibility control ([`show`](https://vpype.readthedocs.io/en/stable/reference.html#show)). -- Geometry **statistics** extraction ([`stat`](https://vpype.readthedocs.io/en/stable/reference.html#stat)). +- Easy to use **CLI** interface with integrated help (`vpype --help`and `vpype COMMAND --help`) and support for arbitrary units (e.g. `vpype read input.svg translate 3cm 2in`). +- First-class **multi-layer support** with global or per-layer processing (e.g. `vpype COMMANDNAME --layer 1,3`) and optionally-probabilistic layer edition commands ([`lmove`](https://vpype.readthedocs.io/en/latest/reference.html#lmove), [`lcopy`](https://vpype.readthedocs.io/en/latest/reference.html#lcopy), [`ldelete`](https://vpype.readthedocs.io/en/latest/reference.html#ldelete), [`lswap`](https://vpype.readthedocs.io/en/latest/reference.html#lswap), [`lreverse`](https://vpype.readthedocs.io/en/latest/reference.html#lreverse)). +- Support for **per-layer and global properties**, which acts as metadata and is used by multiple commands and plug-ins. +- Support for [**property**](https://vpype.readthedocs.io/en/latest/fundamentals.html#property-substitution) and [**expression substitution**](https://vpype.readthedocs.io/en/latest/fundamentals.html#expression-substitution) in CLI user input. +- Support for complex, **per-layer** processing ([`perlayer`](https://vpype.readthedocs.io/en/latest/reference.html#perlayer)). +- Powerful hardware-accelerated **display** command with adjustable units, optional per-line coloring, optional pen-up trajectories display and per-layer visibility control ([`show`](https://vpype.readthedocs.io/en/latest/reference.html#show)). +- Geometry **statistics** extraction ([`stat`](https://vpype.readthedocs.io/en/latest/reference.html#stat)). - Support for **command history** recording (`vpype -H [...]`) - Support for **RNG seed** configuration for generative plug-ins (`vpype -s 37 [...]`). #### Input/Output -- Single- and multi-layer **SVG input** with adjustable precision, parallel processing for large SVGs, and supports percent or missing width/height ([`read`](https://vpype.readthedocs.io/en/stable/reference.html#read)). -- Support for **SVG output** with fine layout control (page size and orientation, centering), layer support with custom layer names, optional display of pen-up trajectories, various option for coloring ([`write`](https://vpype.readthedocs.io/en/stable/reference.html#write)). +- Single- and multi-layer **SVG input** with adjustable precision, parallel processing for large SVGs, and supports percent or missing width/height ([`read`](https://vpype.readthedocs.io/en/latest/reference.html#read)). +- Support for **SVG output** with fine layout control (page size and orientation, centering), layer support with custom layer names, optional display of pen-up trajectories, various option for coloring ([`write`](https://vpype.readthedocs.io/en/latest/reference.html#write)). - Support for **HPGL output** config-based generation of HPGL code with fine layout control (page size and orientation, centering). +- Support for pattern-based **file collection** processing ([`forfile`](https://vpype.readthedocs.io/en/latest/reference.html#forfile)). #### Layout and transforms - Easy and flexible **layout** command for centring and fitting to margin with selectable le horizontal and vertical alignment - ([`layout`](https://vpype.readthedocs.io/en/stable/reference.html#layout)). -- Powerful **transform** commands for scaling, translating, skewing and rotating geometries ([`scale`](https://vpype.readthedocs.io/en/stable/reference.html#scale), [`translate`](https://vpype.readthedocs.io/en/stable/reference.html#translate), [`skew`](https://vpype.readthedocs.io/en/stable/reference.html#skew), [`rotate`](https://vpype.readthedocs.io/en/stable/reference.html#rotate)). -- Support for **scaling** and **cropping** to arbitrary dimensions ([`scaleto`](https://vpype.readthedocs.io/en/stable/reference.html#scaleto), [`crop`](https://vpype.readthedocs.io/en/stable/reference.html#crop)). -- Support for **trimming** geometries by an arbitrary amount ([`trim`](https://vpype.readthedocs.io/en/stable/reference.html#trim)). -- Arbitrary **page size** definition ([`pagesize`](https://vpype.readthedocs.io/en/stable/reference.html#pagesize)). + ([`layout`](https://vpype.readthedocs.io/en/latest/reference.html#layout)). +- Powerful **transform** commands for scaling, translating, skewing and rotating geometries ([`scale`](https://vpype.readthedocs.io/en/latest/reference.html#scale), [`translate`](https://vpype.readthedocs.io/en/latest/reference.html#translate), [`skew`](https://vpype.readthedocs.io/en/latest/reference.html#skew), [`rotate`](https://vpype.readthedocs.io/en/latest/reference.html#rotate)). +- Support for **scaling** and **cropping** to arbitrary dimensions ([`scaleto`](https://vpype.readthedocs.io/en/latest/reference.html#scaleto), [`crop`](https://vpype.readthedocs.io/en/latest/reference.html#crop)). +- Support for **trimming** geometries by an arbitrary amount ([`trim`](https://vpype.readthedocs.io/en/latest/reference.html#trim)). +- Arbitrary **page size** definition ([`pagesize`](https://vpype.readthedocs.io/en/latest/reference.html#pagesize)). #### Metadata -- Adjust layer **color**, **pen width** and **name** ([`color`](https://vpype.readthedocs.io/en/stable/reference.html#color), [`penwidth`](https://vpype.readthedocs.io/en/stable/reference.html#penwidth), [`name`](https://vpype.readthedocs.io/en/stable/reference.html#name)). -- Apply provided or fully customisable **pen configurations** ([`pens`](https://vpype.readthedocs.io/en/stable/reference.html#pens)). -- Manipulate global and per-layer **properties** ([`propset`](https://vpype.readthedocs.io/en/stable/reference.html#propset), [`propget`](https://vpype.readthedocs.io/en/stable/reference.html#propget), [`proplist`](https://vpype.readthedocs.io/en/stable/reference.html#proplist), [`propdel`](https://vpype.readthedocs.io/en/stable/reference.html#propdel), [`propclear`](https://vpype.readthedocs.io/en/stable/reference.html#propclear)). +- Adjust layer **color**, **pen width** and **name** ([`color`](https://vpype.readthedocs.io/en/latest/reference.html#color), [`penwidth`](https://vpype.readthedocs.io/en/latest/reference.html#penwidth), [`name`](https://vpype.readthedocs.io/en/latest/reference.html#name)). +- Apply provided or fully customisable **pen configurations** ([`pens`](https://vpype.readthedocs.io/en/latest/reference.html#pens)). +- Manipulate global and per-layer **properties** ([`propset`](https://vpype.readthedocs.io/en/latest/reference.html#propset), [`propget`](https://vpype.readthedocs.io/en/latest/reference.html#propget), [`proplist`](https://vpype.readthedocs.io/en/latest/reference.html#proplist), [`propdel`](https://vpype.readthedocs.io/en/latest/reference.html#propdel), [`propclear`](https://vpype.readthedocs.io/en/latest/reference.html#propclear)). #### Plotting optimization -- **Line merging** with optional path reversal and configurable merging threshold ([`linemerge`](https://vpype.readthedocs.io/en/stable/reference.html#linemerge)). -- **Line sorting** with optional path reversal ([`linesort`](https://vpype.readthedocs.io/en/stable/reference.html#linesort)). -- **Line simplification** with adjustable accuracy ([`linesimplify`](https://vpype.readthedocs.io/en/stable/reference.html#linesimplify)). -- Closed paths' **seam location randomization**, to reduce the visibility of pen-up/pen-down artifacts ([`reloop`](https://vpype.readthedocs.io/en/stable/reference.html#reloop)). -- Support for generating **multiple passes** on each line ([`multipass`](https://vpype.readthedocs.io/en/stable/reference.html#multipass)). +- **Line merging** with optional path reversal and configurable merging threshold ([`linemerge`](https://vpype.readthedocs.io/en/latest/reference.html#linemerge)). +- **Line sorting** with optional path reversal ([`linesort`](https://vpype.readthedocs.io/en/latest/reference.html#linesort)). +- **Line simplification** with adjustable accuracy ([`linesimplify`](https://vpype.readthedocs.io/en/latest/reference.html#linesimplify)). +- Closed paths' **seam location randomization**, to reduce the visibility of pen-up/pen-down artifacts ([`reloop`](https://vpype.readthedocs.io/en/latest/reference.html#reloop)). +- Support for generating **multiple passes** on each line ([`multipass`](https://vpype.readthedocs.io/en/latest/reference.html#multipass)). #### Filters -- Support for **filtering** by line lengths or closed-ness ([`filter`](https://vpype.readthedocs.io/en/stable/reference.html#filter)). +- Support for **filtering** by line lengths or closed-ness ([`filter`](https://vpype.readthedocs.io/en/latest/reference.html#filter)). - **Squiggle** filter for shaky-hand or liquid-like styling ([`squiggles`](https://vpype.readthedocs.io/en/latest/reference.html#squiggles)) -- Support for **splitting** all lines to their constituent segments ([`splitall`](https://vpype.readthedocs.io/en/stable/reference.html#splitall)). +- Support for **splitting** all lines to their constituent segments ([`splitall`](https://vpype.readthedocs.io/en/latest/reference.html#splitall)). - Support for **reversing** order of paths within their layers ([`reverse`](https://vpype.readthedocs.io/en/latest/reference.html#reverse)). #### Generation - - Generation of arbitrary **primitives** including lines, rectangles, circles, ellipses and arcs ([`line`](https://vpype.readthedocs.io/en/stable/reference.html#line), [`rect`](https://vpype.readthedocs.io/en/stable/reference.html#rect), [`circle`](https://vpype.readthedocs.io/en/stable/reference.html#circle), [`ellipse`](https://vpype.readthedocs.io/en/stable/reference.html#ellipse), [`arc`](https://vpype.readthedocs.io/en/stable/reference.html#arc)). + - Generation of arbitrary **primitives** including lines, rectangles, circles, ellipses and arcs ([`line`](https://vpype.readthedocs.io/en/latest/reference.html#line), [`rect`](https://vpype.readthedocs.io/en/latest/reference.html#rect), [`circle`](https://vpype.readthedocs.io/en/latest/reference.html#circle), [`ellipse`](https://vpype.readthedocs.io/en/latest/reference.html#ellipse), [`arc`](https://vpype.readthedocs.io/en/latest/reference.html#arc)). - Generation of **text** using bundled Hershey fonts ([`text`](https://vpype.readthedocs.io/en/latest/reference.html#text)) - - Generation of grid-like layouts ([`grid`](https://vpype.readthedocs.io/en/stable/reference.html#grid)). - - Generation of a **frame** around the geometries ([`frame`](https://vpype.readthedocs.io/en/stable/reference.html#frame)). - - Generation of random lines for debug/learning purposes ([`random`](https://vpype.readthedocs.io/en/stable/reference.html#random)) + - Generation of grid-like layouts ([`grid`](https://vpype.readthedocs.io/en/latest/reference.html#grid)). + - Generation of a **frame** around the geometries ([`frame`](https://vpype.readthedocs.io/en/latest/reference.html#frame)). + - Generation of random lines for debug/learning purposes ([`random`](https://vpype.readthedocs.io/en/latest/reference.html#random)) #### Extensibility and API - First-class support for **plug-in** extensions (e.g [vpype-text](https://github.com/abey79/vpype-text), [hatched](https://github.com/abey79/hatched), [occult](https://github.com/LoicGoulefert/occult)). - - Support for **script-based** generation ([`script`](https://vpype.readthedocs.io/en/stable/reference.html#script)). - - Powerful and [well-documented](https://vpype.readthedocs.io/en/stable/api.html) **API** for plug-ins and other plotter generative art projects. + - Support for **script-based** generation ([`script`](https://vpype.readthedocs.io/en/latest/reference.html#script)). + - Powerful and [well-documented](https://vpype.readthedocs.io/en/latest/api.html) **API** for plug-ins and other plotter generative art projects. ## Plug-ins @@ -250,7 +306,7 @@ and much more. ## Contributing Contributions to this project are welcome and do not necessarily require software development skills! Check the -[Contributing section](https://vpype.readthedocs.io/en/stable/contributing.html) of the documentation for more +[Contributing section](https://vpype.readthedocs.io/en/latest/contributing.html) of the documentation for more information. diff --git a/docs/cookbook.rst b/docs/cookbook.rst index 22b3ec1b..56e744c2 100644 --- a/docs/cookbook.rst +++ b/docs/cookbook.rst @@ -8,51 +8,39 @@ Cookbook .. highlight:: bash -Laying out a SVG for plotting -============================= -There are two ways to layout geometries on a page. The preferred way is to use commands such as :ref:`cmd_layout`, :ref:`cmd_scale`, :ref:`cmd_scaleto`, :ref:`cmd_translate`. In particular, :ref:`cmd_layout` handles most common cases -by centering the geometries on page and optionally scaling them to fit specified margins. These commands act on the pipeline and their effect can be previewed using the :ref:`cmd_show` command. The following examples all use this approach. +SVG reading and writing recipes +=============================== -Alternatively, the :ref:`cmd_write` commands offers option such as :option:`--page-size ` and -:option:`--center ` which can also be used to layout geometries. It must be understood that these -options *only* affect the output file and leave the pipeline untouched. Their effect cannot be previewed by the -:ref:`cmd_show` command, even if it placed after the :ref:`cmd_write` command. +.. _faq_pipeline_in_shell_script: +Wrapping a *vpype* pipeline in a shell script +--------------------------------------------- -This command will :ref:`cmd_read` a SVG file, and then :ref:`cmd_write` it to a new SVG file sized to A4 in landscape orientation, with the design centred on the page:: +Optimizing a SVG file is quite possibly the most common use of *vpype*. It usually is done with a pipeline similar to this example:: - $ vpype read input.svg layout --landscape a4 write output.svg + $ vpype read my_file.svg linemerge linesort reloop linesimplify write my_file_optimized.svg -The :ref:`cmd_layout` command implicitly centers the geometries on the page. The :ref:`cmd_pagesize` command can be used -to choose the page size without changing the geometries:: +In particular, it is rather common to name the output file after the input file, maybe with a ``_processed`` suffix. - $ vpype read input.svg pagesize --landscape a4 write output.svg +Such a *vpype* invocation can easily be packaged in a shell script using some simple path expression. Here is the content of such a shell script:: -This command will :ref:`cmd_read` a SVG file and lay it out to 3cm margin with a top vertical alignment (a generally pleasing arrangement for square designs on the portrait-oriented page), and then :ref:`cmd_write` it to a new SVG:: + #!/bin/sh - $ vpype read input.svg layout --fit-to-margins 3cm --valign top a4 write output.svg + vpype read "$1" linemerge linesort reloop linesimplify \ + write "%prop.vp_source.with_stem(prop.vp_source.stem + '_processed')%" -This command will :ref:`cmd_read` a SVG file, :ref:`cmd_scale` it down to a 80% of its original size, and then :ref:`cmd_write` it to a new A5-sized SVG, centred on the page:: +(Shell scripts are typically named with a ``.sh`` extension and should be marked as "executable" to be used. This can be done with the ``chmod +x my_script.sh`` command.) - $ vpype read input.svg scale 0.8 0.8 layout a5 write output.svg +The script might be used as follows:: -This command will :ref:`cmd_read` a SVG file, scale it down to a 5x5cm square (using the :ref:`cmd_scaleto` command), and then :ref:`cmd_write` it to a new A5-sized SVG, centred on the page:: - - $ vpype read input.svg scaleto 5cm 5cm layout a5 write output.svg - -This command will :ref:`cmd_read` a SVG file, :ref:`cmd_crop` it to a 10x10cm square positioned 57mm from the top and left corners of the design, and then :ref:`cmd_write` it to a new SVG whose page size will be identical to the input SVG:: - - $ vpype read input.svg crop 57mm 57mm 10cm 10cm write output.svg - -This command will :ref:`cmd_read` a SVG file, add a single-line :ref:`cmd_frame` around the design, 5cm beyond its bounding box, and then :ref:`cmd_write` it to a new SVG:: - - $ vpype read input.svg frame --offset 5cm write output.svg + $ ./my_script.sh /path/to/my_file.svg +The argument passed to the script is forwarded to *vpype* through the use of ``$1``. Then, the output path provided to the :ref:`cmd_write` command corresponds to the input path, with a ``_processed`` suffix added (e.g. ``/path/to/my_file_processed.svg`` in this case). This is achieved by the ``prop.vp_source.with_stem(prop.vp_source.stem + '_processed')`` expression. Preserve color (or other attributes) when reading SVG -===================================================== +----------------------------------------------------- By default, the :ref:`cmd_read` command sorts geometries into layers based on the input SVG's top-level groups, akin to Inkscape's layers. Stroke color is preserved *only* if it is identical for every geometries within a layer. @@ -70,9 +58,79 @@ Multiple attributes can even be provided:: In this case, a layer will be created for each unique combination of color and stroke width. +.. _faq_files_to_layer: + +Merge multiple SVGs into a multilayer file +------------------------------------------ + +This command will :ref:`cmd_read` two SVG files onto two different layers, then :ref:`cmd_write` them into a single SVG +file:: + + $ vpype \ + forfile "*.svg" \ + read --layer %_i+1% %_path% \ + end \ + write output.svg + + +.. _faq_merge_layers_by_name: + +Load multiple files, merging their layers by name +------------------------------------------------- + +Let us consider a collection of SVG files, each with one or more named layer(s). It could be for example a collection of CMYK SVGs, some of which with all four layers, but other with a sub-set of the layers (say, only "yellow" and "black"). This recipe shows how to load these files, making sure identically-named layers are properly merged. + +Here is the full pipeline:: + + $ vpype \ + eval "names={};n=100" \ + forfile "*.svg" \ + read %_path% \ + forlayer \ + eval "%if _name not in names: names[_name] = n; n = n+1%" \ + lmove %_lid% "%names[_name]%" \ + end \ + end \ + write combined.svg + +This pipeline makes use of two nested blocks and some clever expressions. Let us break down how it works. + +The core idea is to build a dictionary ``names`` which maps "destination" layer IDs to layer name. Destination layer IDs is where geometries will be merged, and we choose a starting layer ID value ``n`` of 100 to avoid interfering with the input file layers. At the beginning, ``names`` is an empty dictionary (``{}``). Here is how it could look at the end of a typical run: + + .. code-block:: python + + names = { + 'cyan': 100, + 'magenta': 101, + 'yellow': 102, + 'black': 103 + } + +The outer block, marked by the ``forfile "*.svg"`` command, iterates over SVG files in the current directory. Each file is first read using ``read %_path%``. Then, we iterate over its layers using the ``forlayer`` block processor. + +This is where it becomes interesting. For each layer, we first test whether its name exists in the ``names`` dictionary. If not, we create a new item in the dictionary with the layer name, and assign the value of ``n``. This is the layer ID at which identically-named layers must lend. Since the layer ID ``n`` is now assigned, we increment its value for the next time an "unknown" layer name is encountered. + +Now that we made sure we have a destination layer ID for the current layer's name, we can move it using the ``lmove %_lid% "%names[_name]%"`` command. Here, ``_lid`` is the current layer ID as set by ``forlayer`` and ``names[_name]`` the destination layer. + +This recipe can be further augmented to arrange each file on a grid. This is covered in the :ref:`faq_merge_to_grid` recipe. + + +.. _faq_export_by_layers: + +Saving each layer as a separate file +------------------------------------ + +Some plotter workflows require a different for each layer, as opposed to a single, multi-layer SVG file. For example, this is often the case for gcode input using the `vpype-gcode `__ plug-in. + +This can be achieved using the :ref:`cmd_forlayer` command:: + + $ vpype read input.svg forlayer write "output_%_name or _lid%.svg" end + +Here, we construct the output file name either based on the layer name if available (which :ref:`cmd_forlayer` stores in the ``_name`` variable), or on the layer ID (``_lid``) otherwise. + Make a previsualisation SVG -=========================== +--------------------------- The SVG output of :ref:`cmd_write` can be used to previsualize and inspect a plot. By default, paths are colored by layer. It can be useful to color each path differently to inspect the result of :ref:`cmd_linemerge`:: @@ -85,134 +143,194 @@ Likewise, pen-up trajectories can be included in the SVG to inspect the result o Note that :option:`write --pen-up` should only be used for previsualization purposes as the pen-up trajectories may end-up being plotted otherwise. The Axidraw software will ignore the layer in which the pen-up trajectories are written, so it is safe to keep them in this particular case. -Optimizing a SVG for plotting -============================= +Layout recipes +============== -This command will :ref:`cmd_read` a SVG file, merge any lines whose endings are less than 0.5mm from each other with :ref:`cmd_linemerge`, and then :ref:`cmd_write` a new SVG file:: +Basic layout examples +--------------------- - $ vpype read input.svg linemerge --tolerance 0.5mm write output.svg +There are two ways to layout geometries on a page. The preferred way is to use commands such as :ref:`cmd_layout`, :ref:`cmd_scale`, :ref:`cmd_scaleto`, :ref:`cmd_translate`. In particular, :ref:`cmd_layout` handles most common cases +by centering the geometries on page and optionally scaling them to fit specified margins. These commands act on the pipeline and their effect can be previewed using the :ref:`cmd_show` command. The following examples all use this approach. -In some cases such as densely connected meshes (e.g. a grid where made of touching square paths), :ref:`cmd_linemerge` may not be able to fully optimize the plot by itself. Using :ref:`cmd_splitall` before breaks everything into its constituent segment and enables :ref:`cmd_linemerge` to perform a more aggressive optimization, at the cost of a increased processing time:: +Alternatively, the :ref:`cmd_write` commands offers option such as :option:`--page-size ` and +:option:`--center ` which can also be used to layout geometries. It must be understood that these +options *only* affect the output file and leave the pipeline untouched. Their effect cannot be previewed by the +:ref:`cmd_show` command, even if it is placed after the :ref:`cmd_write` command. - $ vpype read input.svg splitall linemerge --tolerance 0.5mm write output.svg -This command will :ref:`cmd_read` a SVG file, simplify its geometry by reducing the number of segments in a line until they're a maximum of 0.1mm from each other using :ref:`cmd_linesimplify`, and then :ref:`cmd_write` a new SVG file:: +This command will :ref:`cmd_read` a SVG file, and then :ref:`cmd_write` it to a new SVG file sized to A4 in landscape orientation, with the design centred on the page:: - $ vpype read input.svg linesimplify --tolerance 0.1mm write output.svg + $ vpype read input.svg layout --landscape a4 write output.svg -This command will :ref:`cmd_read` a SVG file, randomise the seam location for paths whose beginning and end points are a maximum of 0.03mm from each other with :ref:`cmd_reloop`, and then :ref:`cmd_write` a new SVG file:: +The :ref:`cmd_layout` command implicitly centers the geometries on the page. The :ref:`cmd_pagesize` command can be used +to choose the page size without changing the geometries:: - $ vpype read input.svg reloop --tolerance 0.03mm write output.svg + $ vpype read input.svg pagesize --landscape a4 write output.svg -This command will :ref:`cmd_read` a SVG file, extend each line with a mirrored copy of itself three times using :ref:`cmd_multipass`, and then :ref:`cmd_write` a new SVG file. This is useful for pens that need a few passes to get a good result:: +This command will :ref:`cmd_read` a SVG file and lay it out to 3cm margin with a top vertical alignment (a generally pleasing arrangement for square designs on the portrait-oriented page), and then :ref:`cmd_write` it to a new SVG:: - $ vpype read input.svg multipass --count 3 write output.svg + $ vpype read input.svg layout --fit-to-margins 3cm --valign top a4 write output.svg -This command will :ref:`cmd_read` a SVG file, use :ref:`cmd_linesort` to sort the lines to minimise pen-up travel distance, and then :ref:`cmd_write` a new SVG file:: +This command will :ref:`cmd_read` a SVG file, :ref:`cmd_scale` it down to 80% of its original size, and then :ref:`cmd_write` it to a new A5-sized SVG, centred on the page:: - $ vpype read input.svg linesort write output.svg + $ vpype read input.svg scale 0.8 0.8 layout a5 write output.svg +This command will :ref:`cmd_read` a SVG file, scale it down to a 5x5cm square (using the :ref:`cmd_scaleto` command), and then :ref:`cmd_write` it to a new A5-sized SVG, centred on the page:: -Merging multiple designs into a multi-layer SVG -=============================================== + $ vpype read input.svg scaleto 5cm 5cm layout a5 write output.svg -This command will :ref:`cmd_read` two SVG files onto two different layers, then :ref:`cmd_write` them into a single SVG -file:: +This command will :ref:`cmd_read` a SVG file, :ref:`cmd_crop` it to a 10x10cm square positioned 57mm from the top and left corners of the design, and then :ref:`cmd_write` it to a new SVG whose page size will be identical to the input SVG:: - $ vpype read --single-layer --layer 1 input1.svg read --single-layer --layer 2 input2.svg write output.svg + $ vpype read input.svg crop 57mm 57mm 10cm 10cm write output.svg -Note the use of :option:`--single-layer `. It is necessary to make sure that the input SVG is -merged into a single layer and is necessary to enable the :option:`--layer ` option. +This command will :ref:`cmd_read` a SVG file, add a single-line :ref:`cmd_frame` around the design, 5cm beyond its bounding box, and then :ref:`cmd_write` it to a new SVG:: -This command will :ref:`cmd_read` two SVG files onto two different layers, rotate one layer 180 degrees, then -:ref:`cmd_write` both layers into a single SVG file:: + $ vpype read input.svg frame --offset 5cm write output.svg - $ vpype read --single-layer --layer 1 input1.svg read --single-layer --layer 2 input2.svg rotate --layer 2 180 write output.svg -This command will :ref:`cmd_read` two SVG files onto two different layers, :ref:`cmd_translate` (i.e. move) one of them -0.1cm down and to the right, and then :ref:`cmd_write` both layers into a single SVG file with custom layer names -"Pen 1" and "Pen 2":: +Cropping and framing geometries +------------------------------- - $ vpype read --single-layer --layer 1 input1.svg read --single-layer --layer 2 input2.svg translate --layer 2 0.1cm 0.1cm write --layer-label "Pen %d" output.svg +The following pipeline can be used to crop geometries and frame them with a given margin:: + $ vpype \ + read input.svg \ + eval "m=2*cm; w, h = prop.vp_page_size" \ + crop %m% %m% "%w-2*m%" "%h-2*m%" \ + rect %m% %m% "%w-2*m%" "%h-2*m%" \ + write output.svg -Filtering out small lines -========================= -In some cases (for example when using Blender's freestyle renderer), SVG files can contain a lot of tiny lines which -significantly increase the plotting time and may be detrimental to the final look. These small lines can easily be -removed thanks to the :ref:`cmd_filter` command:: +.. _faq_merge_to_grid: - $ vpype read input.svg filter --min-length 0.5mm write output.svg +Laying out multiple SVGs on a grid +---------------------------------- +The :ref:`cmd_grid` command can be used to layout multiple SVGs onto a regular grid. This recipe shows how. -.. _faq_custom_config_file: +The basic idea is covered by the following pipeline:: -Creating a custom configuration file -==================================== + $ vpype \ + eval "files=glob('*.svg')" \ + eval "cols=3; rows=ceil(len(files)/cols)" \ + grid -o 10cm 15cm "%cols%" "%rows%" \ + read --no-fail "%files[_i] if _i < len(files) else ''%" \ + layout -m 0.5cm 10x15cm \ + end \ + write combined.svg -Some of *vpype*'s features (such as HPGL export) or plug-in (such as `vpype-gcode `_) can be customized using a configuration file using the `TOML `_ format. The documentation of the features or plug-in using such a configuration file explains what it should contain. This section focuses on how a custom config file is made available to *vpype*. +Here are the key insights to understand how this pipeline works: -The most common way is to create a `.vpype.toml` file at the root of your user directory, e.g.: + * An expression with the ``glob()`` function (see :ref:`fundamentals_expr_builtins`) is used to create a list of files to include on the grid. + * Another expression computes the number of rows needed to include all files, given a number of column (hard-coded to 3 in this case). + * The :ref:`cmd_grid` command uses expressions again as argument to use the previously computed column and row count. + * For the :ref:`cmd_read` command, multiple tricks are used. The variable ``_i`` is set by the :ref:`cmd_grid` command and corresponds to the cell counter. We use it to look up the file path to read from our file list. We must however handle the last row, which might be incomplete. This is done with a conditional expression (see :ref:`fundamentals_conditional_expr`) which returns an empty path ``''`` if the cell index is beyond the end of the file list. Normally, the :ref:`cmd_read` would fail when passed a non-existing path. This is avoided by using the ``--no-fail`` option. + * Finally, the :ref:`cmd_layout` command fits the SVGs in the cell with a margin. -- ``C:\Users\username\.vpype.toml`` on Windows -- ``/Users/username/.vpype.toml`` on Mac -- ``/home/username/.vpype.toml`` on Linux +One limitation of the pipeline above is that it will merge layers by their ID, disregarding properties such as layer name or color. In some cases, this may be an issue. Depending on the nature of the input SVGs, this can be addressed by reading each file in a different layer, like in :ref:`faq_files_to_layer`. This can be done by simply adding the ``--layer %_i+1%`` option to the :ref:`cmd_read` command. -If such a file exists, it will be automatically loaded by *vpype* whenever it is used. +When input SVGs have layer names, they can be used to merge similarly named layers together. This is done by the following pipeline:: -.. note:: + $ vpype \ + eval "files=glob('*.svg')" \ + eval "cols=3; rows=ceil(len(files)/cols)" \ + eval "names={};n=100" \ + grid -o 10cm 15cm "%cols%" "%rows%" \ + read --no-fail "%files[_i] if _i < len(files) else ''%" \ + layout -m 0.5cm 10x15cm \ + forlayer \ + eval "%if _name not in names: names[_name] = n; n = n+1%" \ + lmove %_lid% "%names[_name]%" \ + end \ + end \ + write combined.svg - The ``.`` prefix in the file name will make the file **hidden** on most systems. This naming is typical for configuration files in the Unix world. +See :ref:`faq_merge_layers_by_name` for an explanation on how this works. +Given the number of parameters involved, it may be useful to make these pipelines interactive (see :ref:`faq_interactive_pipelines`). Using a :ref:`command file ` is also a nice way to make easy to reuse. Here is an example of command file:: -Alternatively, a configuration file may be provided upon invocation of *vpype* using the ``--confg`` option (or ``-c`` for short), e.g.:: + # Content of file grid.vpy + # Ask user for some information, using sensible defaults. + eval "files=glob(input('Files [*.svg]? ') or '*.svg')" # glob() creates a list of file based on a pattern + eval "cols=int(input('Number of columns [3]? ') or 3)" + eval "rows=ceil(len(files)/cols)" # the number of rows depends on the number of files + eval "col_width=convert_length(input('Column width [10cm]? ') or '10cm')" # convert_length() converts string like '3cm' to pixels + eval "row_height=convert_length(input('Row height [10cm]? ') or '10cm')" + eval "margin=convert_length(input('Margin [0.5cm]? ') or '0.5cm')" + eval "output_path=input('Output path [output.svg]? ') or 'output.svg'" - (vpype_venv) $ vpype --config my_config_file.toml [...] + # Create a grid with provided parameters. + grid -o %col_width% %row_height% %cols% %rows% -Note that *vpype* does not "remember" of such configuration file and the ``--config`` option and it must be specified on each invocation. + # Read the `_i`-th file. The last row may be incomplete so we use an empty path and `--no-fail`. + read --no-fail "%files[_i] if _i < len(files) else ''%" -.. note:: + # Layout the file in the cell. + layout -m %margin% %col_width%x%row_height% + end - *vpype* is bundled with a `configuration file `_. It is strongly discouraged to edit this file as it will be overwritten each time *vpype* is installed or updated. + # wWrite the output file. + write "%output_path%" +It can be used as follows:: -.. _faq_custom_pen_config: + $ vpype -I grid.vpy + Files [*.svg]? + Number of columns [3]? 4 + Column width [10cm]? + Row height [10cm]? 15cm + Margin [0.5cm]? + Output path [output.svg]? -Creating a custom pen configuration -=================================== +The various parameters are queried and if nothing is provided as input, sensible defaults are used. -Pen configurations associate names, colors, and/or pen widths to specific layers and are applied by the :ref:`cmd_pens` -command. For example, the included ``cmyk`` pen configuration sets the name and color or layers 1 to 4 to cyan, magenta, -yellow, resp. black, while leaving pen widths unchanged. New pen configurations can be defined in a custom config file -(see :ref:`faq_custom_config_file`). -Pen configurations must conform to the following format to be valid: +Processing recipes +=================== - .. code-block:: toml +Optimizing a SVG for plotting +----------------------------- - [pen_config.my_pen_config] # my_pen_config is this pen configuration's name - layers = [ - # for each layer, a layer_id must be provided, but name, color and - # pen_width are optional - { layer_id = 1, name = "black layer", color = "black", pen_width = "0.15mm" }, +This command will :ref:`cmd_read` a SVG file, merge any lines whose endings are less than 0.5mm from each other with :ref:`cmd_linemerge`, and then :ref:`cmd_write` a new SVG file:: - # any valid CSS color string and length unit may be used - { layer_id = 2, name = "red layer", color = "#e00", pen_width = "0.05in" }, + $ vpype read input.svg linemerge --tolerance 0.5mm write output.svg - # any attribute may be omitted, except layer_id - { layer_id = 4, color = "#00de00" }, +In some cases such as densely connected meshes (e.g. a grid where made of touching square paths), :ref:`cmd_linemerge` may not be able to fully optimize the plot by itself. Using :ref:`cmd_splitall` before :ref:`cmd_linemerge` breaks geometries into their constituent segments and enables :ref:`cmd_linemerge` to perform a more aggressive optimization, at the cost of an increased processing time:: - # etc. (a pen configuration may have an arbitrary number of layers defined) - ] + $ vpype read input.svg splitall linemerge --tolerance 0.5mm write output.svg -The above pen configuration can be used by referring to its name, in this case ``my_pen_config``:: +This command will :ref:`cmd_read` a SVG file, simplify its geometry by reducing the number of segments in a line until they're a maximum of 0.1mm from each other using :ref:`cmd_linesimplify`, and then :ref:`cmd_write` a new SVG file:: - $ vpype [...] pens my_pen_config [...] + $ vpype read input.svg linesimplify --tolerance 0.1mm write output.svg + +This command will :ref:`cmd_read` a SVG file, randomise the seam location for paths whose beginning and end points are a maximum of 0.03mm from each other with :ref:`cmd_reloop`, and then :ref:`cmd_write` a new SVG file:: + + $ vpype read input.svg reloop --tolerance 0.03mm write output.svg + +This command will :ref:`cmd_read` a SVG file, extend each line with a mirrored copy of itself three times using :ref:`cmd_multipass`, and then :ref:`cmd_write` a new SVG file. This is useful for pens that need a few passes to get a good result:: + $ vpype read input.svg multipass --count 3 write output.svg + +This command will :ref:`cmd_read` a SVG file, use :ref:`cmd_linesort` to sort the lines to minimise pen-up travel distance, and then :ref:`cmd_write` a new SVG file:: + + $ vpype read input.svg linesort write output.svg + + +Filtering out small lines +------------------------- + +In some cases (for example when using Blender's freestyle renderer), SVG files can contain a lot of tiny lines which +significantly increase the plotting time and may be detrimental to the final look. These small lines can easily be +removed thanks to the :ref:`cmd_filter` command:: + + $ vpype read input.svg filter --min-length 0.5mm write output.svg + + +HPGL export recipes +=================== Converting a SVG to HPGL -======================== +------------------------ For vintage plotters, the :ref:`cmd_write` command is capable of generating HPGL code instead of SVG. HPGL output format is automatically selected if the output path file extension is ``.hpgl``. Since HPGL coordinate systems vary widely from @@ -238,7 +356,7 @@ use:: Defining a default HPGL plotter device -====================================== +-------------------------------------- If you are using the same type of plotter regularly, it may be cumbersome to systematically add the :option:`--device ` option to the :ref:`cmd_write` command. The default device can be set in a configuration file (see @@ -253,7 +371,7 @@ If you are using the same type of plotter regularly, it may be cumbersome to sys .. _faq_custom_hpgl_config: Creating a custom configuration file for a HPGL plotter -======================================================= +------------------------------------------------------- The configuration for a number of HPGL plotter is bundled with *vpype* (run ``vpype write --help`` for a list). If your plotter is not included, it is possible to define your own plotter configuration in a custom configuration file @@ -328,7 +446,7 @@ aspects that require specific caution: * ``paper_size`` *must* be defined in the order corresponding to the plotter's native X/Y axis orientation. In the example above, the long side is specified before the short side because the plotter's native coordinate system has - its X axis oriented along the long side the Y axis oriented along the short side of the page. + its X axis oriented along the long side and the Y axis oriented along the short side of the page. * ``origin_location`` defines the physical location of (0, 0) plotter unit coordinate on the page, with respect to the top-left corner of the page in the orientation implied by ``paper_size``. In the example above, since the long edge is defined first, ``origin_location`` is defined based on the top-left corner in landscape orientation. @@ -338,7 +456,7 @@ aspects that require specific caution: Using arbitrary paper size with HPGL output -=========================================== +------------------------------------------- Some plotters such as the Calcomp Designmate support arbitrary paper sizes. Exporting HPGL with arbitrary paper size requires a specific paper configuration. *vpype* ships with the ``flex`` and ``flexl`` configurations for the @@ -371,8 +489,103 @@ use the ``flexl`` paper configuration because the paper is loaded in landscape o SVG is already sized and laid out according to the paper size, the :ref:`cmd_layout` command may be omitted. +Customizing *vpype* +=================== + +.. _faq_custom_config_file: + +Creating a custom configuration file +------------------------------------ + +Some of *vpype*'s features (such as HPGL export) or plug-in (such as `vpype-gcode `_) can be customized using a configuration file using the `TOML `_ format. The documentation of the features or plug-in using such a configuration file explains what it should contain. This section focuses on how a custom config file is made available to *vpype*. + +The most common way is to create a `.vpype.toml` file at the root of your user directory, e.g.: + +- ``C:\Users\username\.vpype.toml`` on Windows +- ``/Users/username/.vpype.toml`` on Mac +- ``/home/username/.vpype.toml`` on Linux + +If such a file exists, it will be automatically loaded by *vpype* whenever it is used. + +.. note:: + + The ``.`` prefix in the file name will make the file **hidden** on most systems. This naming is typical for configuration files in the Unix world. + + +Alternatively, a configuration file may be provided upon invocation of *vpype* using the ``--config`` option (or ``-c`` for short), e.g.:: + + (vpype_venv) $ vpype --config my_config_file.toml [...] + +Note that *vpype* does not "remember" the provided configuration file. The ``--config`` option must thus be provided on each invocation. + +.. note:: + + *vpype* is bundled with a `configuration file `_. It is strongly discouraged to edit this file as it will be overwritten each time *vpype* is installed or updated. + + +.. _faq_custom_pen_config: + +Creating a custom pen configuration +----------------------------------- + +Pen configurations associate names, colors, and/or pen widths to specific layers and are applied by the :ref:`cmd_pens` +command. For example, the included ``cmyk`` pen configuration sets the name and color or layers 1 to 4 to cyan, magenta, +yellow, resp. black, while leaving pen widths unchanged. New pen configurations can be defined in a custom config file +(see :ref:`faq_custom_config_file`). + +Pen configurations must conform to the following format to be valid: + + .. code-block:: toml + + [pen_config.my_pen_config] # my_pen_config is this pen configuration's name + layers = [ + # for each layer, a layer_id must be provided, but name, color and + # pen_width are optional + { layer_id = 1, name = "black layer", color = "black", pen_width = "0.15mm" }, + + # any valid CSS color string and length unit may be used + { layer_id = 2, name = "red layer", color = "#e00", pen_width = "0.05in" }, + + # any attribute may be omitted, except layer_id + { layer_id = 4, color = "#00de00" }, + + # etc. (a pen configuration may have an arbitrary number of layers defined) + ] + +The above pen configuration can be used by referring to its name, in this case ``my_pen_config``:: + + $ vpype [...] pens my_pen_config [...] + + +Miscellaneous recipes +===================== + +.. _faq_interactive_pipelines: + +Create interactive scripts with ``input()`` +------------------------------------------- + +The Python :func:`input` function is available in :ref:`expressions `. It can be used to interactively query the use for parameter values. For example, this pipeline asks the user for a margin value and uses it to layout a SVG:: + + $ vpype \ + eval "margin = float(input('Margin in cm? '))" \ + read input.svg \ + layout --fit-to-margins %margin*cm% a4 \ + write output.svg + Margin in cm? 3 + +This pattern can be improved by providing a default value, allowing the user to simply type to use it:: + + $ vpype \ + eval "margin = float(input('Margin in cm [3cm]? ') or 3)" \ + ... + +This works because of the particular way in which the ``or`` operator behaves. It evaluates to the first operand whose truthiness is :data:`True`. When the user directly hits , the first operand is an empty string, whose truthiness is :data:`False`. The ``or`` expression thus evaluates to the second operand in this case. + +See :ref:`faq_merge_to_grid` for a real-world example that makes use of this pattern. + Batch processing many SVG with bash scripts and ``parallel`` -============================================================ +------------------------------------------------------------ Computers offer endless avenues for automation, which depend on OS and the type of task at hand. Here is one way to easily process a large number of SVG with the same *vpype* pipeline. This approach relies on the @@ -397,25 +610,13 @@ them:: $ parallel --dry-run --plus vpype read {} linemerge linesort write {/.svg/_processed.svg} ::: *.svg -Repeating a design on a grid -============================ - -This command will draw a collection of 3x3cm :ref:`circles ` in a 5x8 grid, then :ref:`cmd_show` the results using matplotlib:: - - $ vpype begin \ - grid 5 8 \ - circle 0 0 3cm \ - end \ - show - - External scripts -================ +---------------- The :ref:`cmd_script` command is a very useful generator that relies on an external Python script to produce geometries. Its use is demonstrated by the `alien.sh` and `alien2.sh` examples. A path to a Python file must be passed as argument. The file must implement a `generate()` function which returns a Shapely `MultiLineString` object. This is very easy -and explained in the [Shapely documentation](https://shapely.readthedocs.io/en/latest/manual.html#collections-of-lines). +and explained in the `Shapely documentation `__. diff --git a/docs/fundamentals.rst b/docs/fundamentals.rst index cc0d67ef..0a2b9344 100644 --- a/docs/fundamentals.rst +++ b/docs/fundamentals.rst @@ -11,7 +11,7 @@ Fundamentals Pipeline ======== -To use *vpype*, you compose 'pipelines' of 'commands'. In a given pipeline, geometries are passed from command to command, starting with the first all the way to the last. +To use *vpype*, you compose "pipelines" of "commands". In a given pipeline, geometries are passed from command to command, starting with the first all the way to the last. .. image:: images/pipeline.svg @@ -54,10 +54,11 @@ Help on each command is also available by running the help option on that comman Lines and layers ================ -The geometries passed from command to command are organised as a collection of layers, each containing a collection of paths. +.. figure:: images/layers.svg + :figwidth: 300px + :align: right -.. image:: images/layers.svg - :width: 300px +The geometries passed from command to command are organised as a collection of layers, each containing a collection of paths. The primary purpose of layers in *vpype* is to create or process files for multicolored plots, where each layer contains geometries to be drawn with a specific pen or color. In *vpype*, layers are identified by a non-zero, positive integer (e.g. 1, 2,...). You can have as many layers as you want, memory permitting. @@ -65,7 +66,9 @@ Each layer consists of an ordered collection of paths. In *vpype*, paths are so- Curved paths are not supported *per se*. Instead, curves are converted into linear segments that are small enough to approximate curvature in a way that is invisible in the final plot. For example, the :ref:`cmd_read` command transforms all curved SVG elements (such as circles or bezier paths) into paths made of segments, using a maximum segment size that can be set by the user (so-called "quantization"). This design choice makes *vpype* very flexible and easy to develop, with no practical impact on final plot quality, but is the primary reason why *vpype* is not fit to be (and is not meant as) a general-purpose vector graphics processing tool. -One downside of using polylines to approximate curved element is a potential increase in output file size. For example, three numbers are sufficient to describe a circle, but 10 to 100 segments may be needed to approximate it sufficiently well for plotting. When this becomes an issue, tuning the quantization parameters with the ``-q`` option or using the :ref:`cmd_linesimplify` command can help. +.. note:: + + One downside of using polylines to approximate curved element is a potential increase in output file size. For example, three numbers are sufficient to describe a circle, but 10 to 100 segments may be needed to approximate it sufficiently well for plotting. When this becomes an issue, tuning the quantization parameters with the ``-q`` option or using the :ref:`cmd_linesimplify` command can help. .. _fundamentals_commands: @@ -73,7 +76,7 @@ One downside of using polylines to approximate curved element is a potential inc Command taxonomy ================ -Commands come in three different types: *generators*, *layer processors* and *global processors*. Although it is not strictly necessary to understand the difference between them to use *vpype*, it helps to have a good grasp on how they work, and is very useful if you plan on writing your own :ref:`plug-ins `. +Commands come in four different types: *generators*, *layer processors*, *global processors*, and *block processors*. The first three are covered in this section. The block processors are different in the sense they act on the flow of execution of the pipeline. They are covered in the :ref:`fundamentals_blocks` section below. .. image:: images/command_types.svg :width: 600px @@ -84,15 +87,15 @@ Commands come in three different types: *generators*, *layer processors* and *gl Generators ---------- -Generators add new geometries to a target layer, ignoring (but preserving) any content already existing in the layer. Other layers' content is not affected. They accept a ``--layer TARGET`` option to control which layer should receive the new geometries. By default, the target layer of the previous generator command is used, or layer 1 if the generator is the first. Here's an example:: +Generators add new geometries to a target layer, preserving any content already existing in the layer. The content of the other layers is not affected. They accept a ``--layer TARGET`` option to control which layer should receive the new geometries. By default, the target layer of the previous generator command is used, or layer 1 for the first generator of the pipeline. Here's an example:: $ vpype line --layer 3 0 0 1cm 1cm circle 0.5cm 0.5cm 0.3cm -This command will first draw a :ref:`cmd_line` on layer 3 from the point (0,0) a point at (1cm, 1cm), then it will draw a :ref:`cmd_circle` also on layer 3 (defaulting to the target of the previous command) centred on the point (0.5cm, 0.5cm), with a radius of 0.3cm. +This pipeline will first draw a :ref:`cmd_line` on layer 3 from the point (0,0) to the point at (1cm, 1cm), then it will draw a :ref:`cmd_circle` also on layer 3 centred on the point (0.5cm, 0.5cm), with a radius of 0.3cm. For generators, ``--layer new`` can be used to generate geometries in a new, empty layer with the lowest possible number identifier. -A few more examples of generators include: +The following commands are further examples of generators: * :ref:`cmd_rect`: generates a rectangle, with optional rounded angles * :ref:`cmd_ellipse`: generates lines approximating an ellipse @@ -105,17 +108,18 @@ A few more examples of generators include: Layer processors ---------------- -Unlike generators, layer processors generally don't produce new paths but instead modify existing ones on a layer-by-layer basis. This means that the way a layer processor changes one layer's content has no bearing on how it will affect another layer. Let's consider for example :ref:`cmd_linemerge`. This command looks for paths whose ends are close to one another (according to some tolerance) and merges them to avoid unnecessary pen-up/pen-down operations by the plotter. Since :ref:`cmd_linemerge` is a layer processor, it will only merge paths within the same layer. +Layer processor operate on a layer-by-layer basis, modifying, complementing, or otherwise processing their content. The way a layer processor changes one layer's content has no bearing on how it will affect another layer. For example, the :ref:`cmd_linemerge` command looks for paths whose ends are close to one another (according to some tolerance) and merges them to avoid unnecessary pen-up/pen-down operations by the plotter. It does this within strictly within each layer and will not merge paths from different layers. -Layer processors accept a ``--layer TARGET[,TARGET[,...]]`` option to specify one or more layer on which they should be applied. Here are some examples:: +Like generators, layer processors accept a ``--layer`` option, but, in this case, multiple layers may be specified. Also, if the ``--layer`` option is omitted, they default to processing all existing layers. Here are some examples:: - $ vpype [...] crop --layer 1 0 0 10cm 10cm - $ vpype [...] crop --layer 1,2,4 0 0 10cm 10cm - $ vpype [...] crop --layer all 0 0 10cm 10cm + $ vpype [...] crop --layer 1 0 0 10cm 10cm # crop layer 1 only + $ vpype [...] crop --layer 1,2,4 0 0 10cm 10cm # crop layers 1, 2 and 4 + $ vpype [...] crop --layer all 0 0 10cm 10cm # crop all layers + $ vpype [...] crop 0 0 10cm 10cm # crop all layers -All these commands crop the specified layers to a 10cm x 10cm rectangle with a top-left corner at (0,0). If the ``--layer`` option is omitted, then ``all`` is assumed and the layer process will target every single (existing) layer. Note that if you provide a list of layers, they must be comma separated without any whitespace. +All these commands crop the specified layers to a 10cm x 10cm rectangle with a top-left corner at (0,0). Note that if you provide a list of layers, they must be comma separated without any whitespace. -A few more examples of layer processors include: +Here are a few more examples of layer processors: * :ref:`cmd_translate`: apply a translation to the geometries (i.e. move them) * :ref:`cmd_linesort`: sort paths within the layer in such a way that the distance travelled by the plotter in pen-up position is minimized @@ -127,9 +131,9 @@ A few more examples of layer processors include: Global processors ----------------- -While layer processors are executed multiple times, once for each layer they are targeted to, global processors are executed only once and apply to all layers. Depending on the command, they may or may not have layer-related parameters, although there is no rule about that. +Unlike layer processors, which are executed once for each target layer, global processors are executed once only, and apply to all layers. -For example, the :ref:`cmd_write` command uses all layers in the pipeline to generate a multi-layer SVG file. The :ref:`cmd_rotate`, :ref:`cmd_scale`, :ref:`cmd_scaleto`, and :ref:`cmd_skew` transformation commands are also implemented as global processors because they use the center of the geometry as reference (by default), although they also accept a `--layer` option which makes them behave much like a layer processor. +For examples, the :ref:`cmd_write` command uses all layers in the pipeline to generate a multi-layer SVG file. Likewise, the :ref:`cmd_layout` command considers all layers when laying out geometries on a given page format. Finally, the layer operations commands, such as :ref:`cmd_lmove` or :ref:`cmd_lcopy`, have effects on multiple layers at once. .. _fundamentals_units: @@ -158,31 +162,45 @@ Likewise, angles are interpreted as degrees by default but alternative units may .. _fundamentals_metadata: -Metadata -======== +Properties +========== + +In addition to geometries, the *vpype* pipeline carries metadata, i.e. data that provides information about geometries. This metadata takes the form of *properties* that are either global to the pipeline, or attached to a given layer. Properties are identified by a name, their value can be of arbitrary type (e.g. integer, floating point, color, etc.) and there can be any number of them. -Metadata is data which provides information about other data. In the case of *vpype*, metadata takes the form of *properties* that are either attached to a given layer, or global. Properties are identified by a name and their value can be of arbitrary type (e.g. integer, floating point, color, etc.). There can be any number of global and/or layer properties and it is up to commands (and plug-ins) how they act based (or upon) these properties. +How properties are created, modified, or deleted is up to the commands used in the pipeline. For example, the :ref:`cmd_read` command creates properties based on the input SVG's contents and the :ref:`cmd_write` command considers some properties when writing the output file. +.. _fundamentals_system_properties: + System properties ----------------- -Some properties are referred to as *system properties*. Their name is prefixed with ``vp_`` and they are widely used throughout *vpype*. Currently, the following system properties are defined: +Although there is in general no constraint on the number, name, and type of properties, some do have a special meaning for *vpype*. They are referred to as *system properties* and their name is prefixed with ``vp_``. Currently, the following system properties are defined: + + * ``vp_color`` (:class:`vpype.Color`): the color of a layer (layer property) + * ``vp_pen_width`` (:class:`float`): the pen width of a layer (layer property) + * ``vp_name`` (:class:`str`): the name of a layer (layer property) + * ``vp_page_size`` (two-:class:`tuple` of :class:`float`): the page size (global property) + * ``vp_source`` (:class:`pathlib.Path`): the input file from which the geometries are created (global and/or layer property) + * ``vp_sources`` (:class:`list` of :class:`pathlib.Path`): list of all input files from which geometries are created (global property) + +Many commands act on these properties. For example, the :ref:`cmd_read` command sets these properties according to the imported SVG file's content. The :ref:`cmd_color`, :ref:`cmd_penwidth`, :ref:`cmd_name`, and :ref:`cmd_pens` commands can set these properties to arbitrary values. In particular, the :ref:`cmd_pens` commands can apply a predefined set of values on multiple layers at once, for example to apply a CMYK color scheme (see :ref:`faq_custom_pen_config` for more information). The page size global property is set by the :ref:`cmd_pagesize` and :ref:`cmd_layout` commands, and used by the :ref:`cmd_write` command. + +.. note:: - * ``vp_color``: the color of a layer (layer property) - * ``vp_pen_width``: the pen width of a layer (layer property) - * ``vp_name``: the name of a layer (layer property) - * ``vp_page_size``: the page size (global property) + The ``vp_source`` and ``vp_sources`` properties are somewhat different from the other properties. They exist as a standard way for file-based commands and plug-ins to record the source file(s) from which geometries originate. -Many commands acts on these properties. For example, the :ref:`cmd_read` command sets these properties according to the imported SVG file's content. The :ref:`cmd_color`, :ref:`cmd_penwidth`, :ref:`cmd_name`, and :ref:`cmd_pens` commands can set these properties to arbitrary values. In particular, the :ref:`cmd_pens` commands can apply a predefined set of values on multiple layers at once, for example to apply a CMYK color scheme (see :ref:`faq_custom_pen_config` for more information). The page size global property is set by the :ref:`cmd_pagesize` and :ref:`cmd_layout` commands. + The ``vp_source`` property contains the last input file used, and may be overwritten if subsequent file-based commands are used. For example, the :ref:`cmd_read` command stores the input SVG path in ``vp_source`` as layer property if the ``--layer`` option is used, or as global property otherwise. If multiple :ref:`cmd_read` commands are used, the last one may overwrite the value from the earlier ones. + + To address this limitation, the :ref:`cmd_read` command also *appends* the input SVG path to the ``vp_sources`` global property. The ``vp_sources`` property therefore is a list of *all* source files involved. Third-party developers are strongly encouraged to implement a similar behavior in their file-based plug-ins. SVG attributes properties ------------------------- -The :ref:`cmd_read` command identifies SVG attributes common to all geometries in a given layer and store their value as layer property with a ``svg_`` prefix. For example, if all geometries in a given layer share a ``stroke-dasharray="3 1"`` SVG attribute (either because it is set at the level of the group element, or because it is set in every single geometry elements), a property named ``svg_stroke-dasharray`` with a value of ``"3 1"`` is added to the layer. +In addition to setting system properties, the :ref:`cmd_read` command identifies SVG attributes common to all geometries in a given layer and store their value as layer property with a ``svg_`` prefix. For example, if all geometries in a given layer share a ``stroke-dasharray="3 1"`` SVG attribute (either because it is set at the level of the group element, or because it is set in every single geometry elements), a property named ``svg_stroke-dasharray`` with a value of ``"3 1"`` is added to the layer. -These properties are set for informational and extension purposes, and are mostly ignored by *vpype* commands. One exception is the :ref:`cmd_write` command, which can optionally restore these attributes in the exported SVG file. +These properties are set for informational and extension purposes, and are mostly ignored by built-in commands. The notable exception is the :ref:`cmd_write` command, which can optionally restore these attributes in the exported SVG file. An example of future extension could be a plug-in which detects the ``svg_stroke-dasharray`` property and turns the corresponding layer's lines into their dashed equivalent. Another example would be a plug-in looking for a ``svg_fill`` property and adding the corresponding hatching patterns to reproduce the filled area. @@ -201,14 +219,14 @@ High-level commands such as :ref:`cmd_penwidth` are not the only means of intera .. _fundamentals_property_substitution: -CLI property substitution -------------------------- +Property substitution +--------------------- -Most arguments and options passes to commands via the *vpype* CLI will apply property substitution on the provided input. For example, this command will draw the name of the layer:: +Most arguments and options passed to commands via the *vpype* CLI apply property substitution on the user input. For example, this command will draw the name of the layer:: $ vpype [...] text --layer 1 "{vp_name} layer" [...] -The curly braces indicate that they should be substituted by the content of the property they refer to. In this case, if layer 1 is named "red", the text "red layer" should be drawn by the :ref:`cmd_text` command. Note the use of double quotes. They are needed because curly braces are typically used by shell interpreters such as ``bash`` or ``zsh`` (here, they are also needed to escape the whitespace between ``{vp_name}`` and ``layer``). +The curly braces mark a property substitution pattern which should be substituted by the content of the property they refer to. In this case, if layer 1 is named "red", the text "red layer" is drawn by the :ref:`cmd_text` command. Note the use of double quotes. They are needed because curly braces are typically used by shell interpreters such as ``bash`` or ``zsh``. In this case, they are also needed to escape the whitespace between ``{vp_name}`` and ``layer``. To avoid substitution, curly braces can be escaped by doubling them:: @@ -218,7 +236,7 @@ Numeric arguments and options also support substitutions (though they may result $ vpype pagesize a4 random -n 200 -a "{vp_page_size[0]}" "{vp_page_size[1]}" show -Internally, the substitution is performed using the :meth:`str.format` Python function, which supports a number of customisation options for numerical values. Here are some examples to illustrates the possibilities: +Internally, the substitution is performed using the :meth:`str.format` Python function, which supports a number of customisation options for numerical values. Here are some examples to illustrate the possibilities: .. code-block:: none @@ -231,7 +249,200 @@ Internally, the substitution is performed using the :meth:`str.format` Python fu {vp_color.red} -> 255 {vp_color.red:#02x} -> 0xff -See the `Python documentation `_ for a complete description of the formatting mini-language. +See the `Python documentation `__ for a complete description of the formatting mini-language. + + +.. _fundamentals_expression_substitution: + +Expression substitution +======================= + +Overview +-------- + +Most arguments and options passed via the CLI may contain so-called "expressions", which are Python-like bits of code which *vpype* evaluates and replaces by what they evaluate to. Expressions are marked by enclosing percent characters (``%``). + +Let us consider the following simple example:: + + $ vpype text %3+4% show + +The argument passed to the :ref:`cmd_text` command, namely ``%3+4%``, is enclosed with percent character and thus evaluated as an expression. The expression, namely ``3+4``, evaluates to 7, and thus the number 7 is drawn and displayed by the :ref:`cmd_show` command. + +Expressions do not need to span the entirety of an argument. They can be mixed with regular text, and multiple expressions may be used in a single argument:: + + $ vpype read input.svg layout %3+4%x%7+2%cm write output.svg + +There are two distinct expressions here (``%3+4%`` and ``%7+2%``). Considering the text around them, they collectively evaluate to ``7x9cm``, which happens to be a valid input for the :ref:`cmd_layout` command. + +Most shells (e.g. ``bash``, ``zsh``, etc.) will interpret characters found in all but the simplest expressions. For example, the multiplication operator ``*`` is interpreted as a wildcard by the shell. Parentheses, brackets, and curly braces all have meanings to the shell too. As a result, arguments and options containing expression must often be escaped with quotes, for example:: + + $ vpype text "%round(4**3.2)%" show + +(Here, the function ``round()`` converts its argument to the nearest integer, and ``**`` is the exponentiation operator. This expression thus evaluates to 84.) + +The :ref:`cmd_eval` command is often useful when using expressions. It does nothing but evaluate the expression it is passed. For example, this pipeline draws and displays the text "hello world":: + + $ vpype eval "%txt='hello world'%" text %txt% show + +Since :ref:`cmd_eval` has no other purpose than evaluating an expression, the expression markers ``%`` may be omitted. This is a valid variant of the same pipeline:: + + $ vpype eval "txt='hello world'" text %txt% show + +Finally, the expression marker ``%`` may be escaped by doubling it. The following example draws and displays a single percent character:: + + $ vpype text %% show + + +Basic syntax +------------ + +The syntax of expressions is a sub-set of Python, and is interpreted by the `asteval `_ library. Its `documentation `_ states: + + While the primary goal is evaluation of mathematical expressions, many features and constructs of the Python language are supported by default. These features include array slicing and subscripting, if-then-else conditionals, while loops, for loops, try-except blocks, list comprehension, and user-defined functions. All objects in the asteval interpreter are truly Python objects, and all of the basic built-in data structures (strings, dictionaries, tuple, lists, sets, numpy arrays) are supported, including the built-in methods for these objects. + +There is no shortage of online material covering the basics of Python syntax, which we will not repeat here. The context in which expressions are used in *vpype* is however unusual. This leads to some peculiarities which are discussed in the next few sections. + +Scope and variables +------------------- + +Multiple expressions may be scattered across several commands in a single *vpype* pipeline. They are all evaluated in the same scope. This means that a variable created in one expression is available to subsequent expressions. This is often used in combination with the :ref:`cmd_eval` command to set or compute values which are used multiple times in the pipeline. For example:: + + $ vpype \ + read input.svg \ + eval "m=2*cm; w,h=prop.vp_page_size; w-=2*m;h-=2*m" \ + crop "%m%" "%m%" "%w%" "%h%" \ + rect "%m%" "%m%" "%w%" "%h%" \ + write output.svg + +Here, the expression used with the :ref:`cmd_eval` command creates a variable ``m`` to store the margin size, unpacks the page size property (``vp_page_size``) into two variables (``w`` and ``h``), amd corrects them for the margin. These variables are then used multiple times to crop the geometries and draw a rectangular frame with the given margin. Note that ``cm`` and ``prop`` are built-in symbols, as explained in the next section. + + +.. _fundamentals_expr_builtins: + +Built-in symbols +---------------- + +This section lists and describes the symbols (functions and variables) which are built-in to *vpype* expressions. + +The following standard Python symbols available: + +* Most the Python `built-in `_ classes and functions: + + :func:`abs`, :func:`all`, :func:`any`, :func:`bin`, :class:`bool`, :class:`bytearray`, :class:`bytes`, :func:`chr`, :class:`complex`, :class:`dict`, :func:`dir`, :func:`divmod`, :func:`enumerate`, :func:`filter`, :class:`float`, :func:`format`, :class:`frozenset`, :func:`hash`, :func:`hex`, :func:`id`, :func:`input`, :class:`int`, :func:`isinstance`, :func:`len`, :class:`list`, :func:`map`, :func:`max`, :func:`min`, :func:`oct`, :func:`ord`, :func:`pow`, :class:`range`, :func:`repr`, :func:`reversed`, :func:`round`, :class:`set`, :class:`slice`, :func:`sorted`, :class:`str`, :func:`sum`, :class:`tuple`, :class:`type`, :func:`zip` + +* Functions and constants from the :py:mod:`math` module: + + :func:`acos() `, :func:`acosh() `, :func:`asin() `, :func:`asinh() `, :func:`atan() `, :func:`atan2() `, :func:`atanh() `, :func:`ceil() `, :func:`copysign() `, :func:`cos() `, :func:`cosh() `, :func:`degrees() `, :data:`e() `, :func:`exp() `, :func:`fabs() `, :func:`factorial() `, :func:`floor() `, :func:`fmod() `, :func:`frexp() `, :func:`fsum() `, :func:`hypot() `, :func:`isinf() `, :func:`isnan() `, :func:`ldexp() `, :func:`log() `, :func:`log10() `, :func:`log1p() `, :func:`modf() `, :data:`pi() `, :func:`pow() `, :func:`radians() `, :func:`sin() `, :func:`sinh() `, :func:`sqrt() `, :func:`tan() `, :func:`tanh() `, :func:`trunc() ` + +* Some of the function from the :py:mod:`os.path` module: + + :func:`abspath() `, :func:`basename() `, :func:`dirname() `, :func:`exists() `, :func:`expanduser() `, :func:`isfile() `, :func:`isdir() `, :func:`splitext() ` + +* The :data:`stdin ` stream from the :py:mod:`sys` module. + +In addition, the following *vpype*-specific symbols are available: + +* The ``prop``, ``lprop``, and ``gprop`` property-access objects. + + These special objects provide access to the global or current-layer properties. Properties may be accessed by attribute (e.g. ``%prop.vp_name%``) or indexation (e.g. ``%prop['vp_name']%``). The ``gprop`` object provides access to global properties. The ``lprop`` object provides access to the current layer's properties if available (i.e. within :ref:`generator ` and :ref:`layer processor ` commands). The ``prop`` object looks first for current-layer properties, if any, and then for global properties. + +* Units constants (``px``, ``in``, ``mm``, ``cm``, ``pc``, ``pt``). + + These constants may be used to convert values to CSS pixels unit, which *vpype* uses internally. For example, the expression ``%(3+4)*cm%`` evaluates to the pixel equivalent of 7 centimeters (e.g. ~264.6 pixels). + +* The ``glob(pattern)`` function. + + This function creates a list of paths (of type `pathlib.Path `_) by expending the provided pattern. In addition to the usual wildcards (``*`` and ``**``), this function also expends the home directory (``~``) and environment variables (``$var`` or ``${var}``), similarly to what shells typically do. See :ref:`fundamentals_using_paths` for more info on using paths in expressions. + +* The :func:`convert_length() `, :func:`convert_angle() `, and :func:`convert_page_size() ` functions. + + These functions convert string representations of lengths, angles, respectively page sizes to numerical values. For example, ``%convert_length('4in')%`` evaluates to the pixel equivalent of 4 inches, and ``%convert_page_size('a4')%`` evaluates to the tuple ``(793.70..., 1122.52...)``, which corresponds to the A4 format in pixels. + +* The :class:`Color ` class. + + This class can be used to create color structure from various input such as CSS-compatible strings or individual component (e.g. ``Color("red")``, ``Color("#ff0000)``, and ``Color(255, 0, 0)`` are equivalent). A :class:`Color ` instance evaluates to a string that is compatible with the :ref:`cmd_color` command. + +In addition to the above, block processors define additional variables for expressions used in nested commands. These variables are prefixed by a underscore character ``_`` to distinguish them from symbols that are always available. See :ref:`fundamentals_block_processor_commands` for a list. + + +.. _fundamentals_using_paths: + +Using paths +----------- + +Some properties (such a ``vp_source``, see :ref:`fundamentals_system_properties`) and expression variables (such as ``_path``, set by the :ref:`cmd_forfile` block processor) are instances of :class:`pathlib.Path` from the Python standard library. When evaluated, these objects behave like a string containing the file path and can be directly used with, e.g., the :ref:`cmd_read` command. The following command borrowed from the :ref:`faq_files_to_layer` recipe illustrates this:: + + $ vpype \ + forfile "*.svg" \ + read --layer %_i+1% %_path% \ + end \ + write output.svg + +Here, the ``_path`` variable set by the :ref:`cmd_forfile` block processor is directly used as file path argument for the :ref:`cmd_read` command. + +There is however much more that instances of :class:`pathlib.Path` are capable of. The `Python documentation `__ covers this extensively, but here is a summary for convenience: + + * ``path.name`` is the full name of the file. + * ``path.stem`` is the base name of the file, excluding any file extension. + * ``path.suffix`` is the file extension of the file. + * ``path.parent`` is another :class:`pathlib.Path` instance corresponding to the directory containing the file. + * ``path.with_stem(s)`` is another :class:`pathlib.Path` instance with the stem (i.e. file name excluding extension) replaced by ``s``. + * Path objects can be composited with the ``/`` operator. For example, ``path.parent / "dir" / "file.svg"`` is a :class:`pathlib.Path` instance pointing at a file named "file.svg" in a directory "dir" next to the original file. + +The :ref:`faq_pipeline_in_shell_script` recipe provides a real-world example relying on :class:`pathlib.Path` capabilities. + +Single-line hints +----------------- + +The Python syntax is known for its heavy reliance on line break and indentation (contrary to, e.g., C-derived languages). For *vpype* expressions, this is a disadvantage, as expressions must fit a single line. This section provides a few hints on how useful tasks may be achieved using single-line expressions. + + +.. _fundamental_statement_separator: + +Statement separator +~~~~~~~~~~~~~~~~~~~ + +A single line of Python may contain multiple statements if they are separated with a semicolon (``;``). For example, this can be used to declare multiple variables in a single :ref:`cmd_eval` command:: + + $ vpype eval "a=3; b='hello'" [...] + +The expression evaluates to the last statement. For example, this pipeline draws and displays the number 4:: + + $ vpype eval "a=2" text "%a+=2;a%" show + + +.. _fundamentals_conditional_expr: + +Conditional expressions +~~~~~~~~~~~~~~~~~~~~~~~ + +In most cases, `conditional expressions `_ (also called "ternary operator") are a good replacement for conditional block:: + + $ vpype eval %b=True% text "%'I win' if b else 'I lose'%" show + +This technique is used by the :ref:`faq_merge_to_grid` recipe. + + +Single-line conditionals and loops +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Although conditional and loop statements typically require line breaks and indentation, they *can*, in their simpler form, be used on a single line. For examples, these are syntactically valid and can be used as *vpype* expression: + + .. code-block:: python + + if cond: n += 1 + while cond: n += 1 + for i in range(4): n += i + +It is important to note that, formally, these are Python *statement* (as opposed to *expression*). They thus evaluate to :data:`None` regardless of the actual run-time branching behavior. For example, this draws and displays "None":: + + $ vpype text "%if True: 'hello'%" show + +These constructs are instead typically used to assign variables which are used in subsequent expressions. + +Another limitation is that single-line conditionals and loops cannot be juxtaposed with other statements using the statement separator (see :ref:`fundamental_statement_separator`). In particular, ``a=3; if True: b=4`` is invalid and ``if False: a=3; b=4`` is valid but ``b=4`` is part of the ``if``-clause and is thus never executed in this case. + +Despite their limitations, these constructs can still be useful in real-world situations. For example, the :ref:`faq_merge_layers_by_name` recipe makes use of them. .. _fundamentals_blocks: @@ -239,63 +450,154 @@ See the `Python documentation ` +~~~~~~~~~~~~~~~~~~~~~~ + +As amply illustrated in the previous sections, the :ref:`cmd_grid` block processor is used to create grid layout. It defines the following variables: + +* ``_nx``: the total number of columns (NX) +* ``_ny``: the total number of rows (NY) +* ``_n``: the total number of cells (NX*NY) +* ``_x``: the current column (0 to NX-1) +* ``_y``: the current row (0 to NY-1) +* ``_i``: the current cell (0 to _n-1) + +The :ref:`faq_merge_to_grid` recipe provides a real-world example with the :ref:`cmd_grid` command. + + +:ref:`repeat ` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: images/repeat_example.png + :figwidth: 40% + :align: right + +The :ref:`cmd_repeat` block processor executes the nested pipeline N times, where N is passed as argument. The nested pipeline is initialised without any geometries and, like the :ref:`cmd_grid` command, its output is merged to the outer pipeline. + +The following example creates four layers, each populated with random lines:: + + $ vpype repeat 4 random -l new -a 10cm 10cm -n 30 \ + end pens cmyk show + +The :ref:`cmd_repeat` command defines the following variables: + +* ``_n``: number of repetitions (N) +* ``_i``: counter (0 to N-1) + + +:ref:`forlayer ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :ref:`cmd_forlayer` block processor executes the nested pipeline once per pre-existing layer. The nested pipeline is initialised with empty geometry *except* for the layer being processed. After the pipeline is executed, the corresponding layer is replaced in the outer pipeline and the other ones, if any, merged. + +It defines the following variables: + +* ``_lid`` (:class:`int`): the current layer ID +* ``_name`` (:class:`str`): the name of the current layer +* ``_color`` (:class:`vpype.Color`): the color of the current layer +* ``_pen_width`` (:class:`float`): the pen width of the current layer +* ``_prop``: the properties of the current layer (accessible by item and/or attribute) +* ``_i`` (:class:`int`): counter (0 to _n-1) +* ``_n`` (:class:`int`): number of layers + +.. note:: + + The ``_prop`` object set by :ref:`cmd_forlayer` should not be mistaken with the ``lprop`` built-in object (see :ref:`fundamentals_expr_builtins`). ``_prop`` provides access to the properties of the layer currently iterated on by :ref:`cmd_forlayer`. In contrast, ``lprop`` provides access to the properties of the layer targeted by the current (nested) command. Both layers do not need to be, and often are not, the same. + +The :ref:`faq_export_by_layers` and :ref:`faq_merge_layers_by_name` recipes provide real-world examples of the :ref:`cmd_forlayer` command. + + +:ref:`forfile ` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :ref:`cmd_forfile` block processor specializes with processing multiple input files. It takes a file path pattern as input (e.g. ``*.svg``), expends it as a list of files, and executes the nested pipeline once per file in the list. The nested pipeline is initialized with empty geometries and, after it is executed, its content is merged into the outer pipeline. + +It defines the following variables: + +* ``_path`` (:class:`pathlib.Path`): the file path (see :ref:`fundamentals_using_paths`) +* ``_name`` (:class:`str`): the file name (e.g. ``"input.svg"``) +* ``_parent`` (:class:`pathlib.Path`): the parent directory (see :ref:`fundamentals_using_paths`) +* ``_ext`` (:class:`str`): the file extension (e.g. ``".svg"``) +* ``_stem`` (:class:`str`): the file name without extension (e.g. ``"input"``) +* ``_n`` (:class:`int`): the total number of files +* ``_i`` (:class:`int`): counter (0 to _n-1) + +The :ref:`faq_files_to_layer` and :ref:`faq_merge_layers_by_name` recipes provide real-world examples with the :ref:`cmd_forfile` command. + + +Nested blocks +------------- + +.. figure:: images/random_grid.png + :figwidth: 40% + :align: right + +Blocks can be nested to achieve more complex compositions. Here is an example:: + + $ vpype \ + grid --offset 8cm 8cm 2 3 \ + grid --offset 2cm 2cm 3 3 \ + random --count 20 --area 1cm 1cm \ + frame \ + end \ + frame --offset 0.3cm \ + end \ + layout a4 \ + show .. _fundamentals_command_files: diff --git a/docs/images/block.svg b/docs/images/block.svg deleted file mode 100644 index 68325b43..00000000 --- a/docs/images/block.svg +++ /dev/null @@ -1,3004 +0,0 @@ - - - - - - - - - - -]> - - - - - - - - - begin - command - command - end - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - blockprocessor - - block pipeline - - - - - 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 -x3LManJMKo85ZjUee9NVVKMVDbG7GbMjmarMieV06oiKzlNKrf/aMyFn8a5q0Ig3eOVDhUwuLyfv -hijTOkSt4oemVLRPGtX2QV8SD9G4VD0utJoVPEHD1lxollVoOUN4gpToPB8lljzC6dja8jSjolLZ -E7oaOpdsO7tnEt4ueS7vbGObbUXfa3+S8EjlgvOzda7wR8+0/gpN0l0xVhZP4Tt28fQMq0p3thnN -Jyv43qr4aRPNQ3czJcOcHLoyraHlNCuzhpa2so0dEVEm9ZUFh1xDpDKlogAhAQsqPHiQUCgCQCI8 -OERQmEADQkH9ai1FgADc9Cin0tPiFCwqvzy0JNPg2OwmeDdWiKg48apK3fCKyorIZeeWonPZaW5K -EWWli85lRPg6z6z0I7fvWOjSTi9omyl+8ygLnX2MdUfmSdt8rNyUmnb70TXthiybdlPoZtMOsUb1 -dqboMpt/2iW+jEnLjliHx7N9eTy7tglt0r5CnDxbx+TQVml0T0f0Ma/cOesMPUWUh3m1tsrSr8k1 -OUQn2YqEea/2U3hpI62032036+WZrdSRuyQaf66s4PlsbGMf2cZXnjJB7I19Rmk3nQ== - - - MuONL29c5Wpm/Zlnmbu5ahJJPMviIja9vCLENB8OupKuCGYNk/CsKl+KHiuS2J7viS+zPCpLT7HC -GitSN5+ymqursSqqe5JNXbHMF6J8ISJPo6qzrLNsJdWLJRack7PkRPCqMBe35343516VEjksM1TM -TEcueIWWZDNO5XlyCN0bmchVGnpaaDNppVKrbUo5Vkf7nF6VSKRuitIme4hDWbLZWiLHu9J7auEr -m2T2mSMyEZmNTb1mVE5mQ2RFsNC1rKPyyqGzUqJVEY6d6IaWRuwlHLO74ljV2LmkWQ1OD+uKFdG5 -zLmlM2J3xbSqUkeymGWr2avy7hDVdOxT3xjWnDsmK0Pmd60zlTXWGSvsGS6uaIok/WX23mt6urEy -ZlaIWLeslAhL0VglZdF6LEVEpUXsrkdlZ7xpaZF8/tq2JJFCyrJRvgqiz2p0LJ7ZTcHCMyuR+iAe -Jl6x0qB9yOp2TLoyc4hmk7f8i1WsrznMvLTyHd+zKnlr81WKmOquUuTy1179V8xDpd4itmd7ZYVY -ihTe7TnvqGQH/xfO/e6fD5XK15UjlIhlN9kZgpQ+O/vllI6xduTUqcJihBAHL4sVIz+0wSmDnXKk -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 -v6oF4T/A4rA7iXr/TmEcTbOHJtPgmck3fmwdCFGvPhIHeqTLv79DOEdb1bQ4f241zp9bbXO31nH8 -3DzOX1vX4c51mzy32spmy1a2e77hY/M3fWm+pq+sz9yJ0TNyZHPOts3f+LHVMWT0NUZbY2341mgi -SD5vg5fmeQTpPFFjH5yYLLNmyzNzZPLOd64HLeJ9oMM7jwP4Vuf4ydU4f3E0jyCdNxLz9QzadZ9C -uy7UuOeFGvd6z+Ccr9FTo2/63Gojyb4PBfrVMnUC3lOnhLeDGY5datTwGwgl/FKmhR5pkvt3unN9 -x0tXM3F+PYMYjfUUKuFn2uTaT6Dg34TpvY8it/8JFPwf0JikJeiQ7AlWLPoFLRS/AdGwfSQG/ESN -fT8oMc8XSfYhVf7ZPYRz3Sd85xv3ftLl9j9xCt5TqISfytTQRhIDfqFEvt8TnrN/Du980eSeTQTJ -54ES7T5Rop/N463rNnZsfocbZ/8Q2v2bvLdOM5dW5/TB+SBDvbuJs2tXnTC0G7Rg/AtYKNpTooY2 -02XXZsL03lKihLZTJ1Lln62UGWhTnRi0qUoHtUqX2z/0qGff7LX1mz+1HoSI95kuvbbSJfcrWXa9 -EGOenbN180SNfZ/qlNBGoMLQjvIstIUW9z4OYFuN89fmhxb1bh9w3b/BY/M5fW42EGGerVS5tZks -v3bO39u3ov2sDJwtz9CNyTleNbunUO5b32yZh/gwgtvZryDGu+9zSOdr9tDoHG+bF1rM+zthuXoH -TFf7KM71HUE5X2S594ci9TzQ4Z3fAcN1mr2xWUbulmXmtFmdLdz3QbyrcbhsdI0fGm09q8N49otL -Bm4sOwOHNsu0kWVr8M7qm8A0b7On1mfizGir2p21pt1ZmjqzuWYvrZaR81mu7SLBZxEkrG11dkaO -jObXri3+BWLLmvavPOG6Okkz0NPAqdU2eWp+hwt3Dz3ufZ0t3J95G6tl5LTzjjfuByHq/R3uXN/p -znUcP7fv88X7RpCB3ijy7zNpev8SJtfW+crVOdu3egdMR/MMznUiSD+PNLn9UKHgL1Va+A2EEv6p -0sIvVQq+lzK7fodL93P84r5SZqAdVfrVLmUC3kuaXNsJNOyjTME/yhT8nzjBd5WJwy81Omgribn2 -FGr4niI9/FKlhr5p82sTMf59IUW9L8SYZ/MI0vkdb9zn6dZ9oMI7W0gx7yZy3LOBBvc+ECHeP4oE -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 - - - NV96zTJ75VeV/1Pej59fXix9tsQ+WS7xlB5ppi67J67S71/e/mFW7ES8/pQ10zzlpbHS/F5NJsut -v7zYJZ6s94p9st5Ws4o+J8ur6dE/ZmurfM+TNT/SOGfTKalL+tHj165o40xtpi1nrai1lspZxfqV -nUhzM1lu6+PKv19+FWmk9V56o1t5I815UvnWWi5rzNl6ljfaPGU7tV9lV9e756xPJytS+jVL6zPL -+12rtBMpX+yy3rsxumi9kdb/6Le6Vb7jD7V9qA+1zX55nVor7+wr77TF6/jlfZunrRLHO6t4ac97 -41fTFnHG9am7zNOvyxlzdlql/UjztfIjvdW0tZyRNqVe3bF0dztrlu9eTSQviYQ+LPM0rvlm6TTO -nOX0a7JmS78yx1xFxzLXKtY6qZW5emkrLLuyWPZLO11TWizzNJquybLyY8Z+bctZ3Snb0mgnlR4n -raaQS5efsaRUehVx1355n152YsdT9rUyR1odt5zzk22hTwtNIUmvrFMoV9ZpyKnnHOusrMQ3Umtr -ldTjyZjY67RV6fH+zPh+lb+aripW6fbany7367rFt173r2knnjSxGVwWjXjyqKpqsqprs/RZUXuv -xJat+M5+py/p+2X/es9JiraK789pn2OPb+e/P93iT6T4P/2ze3XlztQ8q/j93Y2rxNhvFSuu4n+e -OcbHF8f2ScqzmkJiV9G9ijhP12TFG/1KPKcr9lWlpVfiWVU/f7pItaeQ2NTf2/C6TqVV0im/IlGc -Z8V3umJtXEVsn5JeUix/UnxzfxXtT9eFcRXt3XB46rj/r+dp4QpXF66qaKONOF6XN2I8aWJb0zVZ -0cYcc452smKOucpVzFbeXMV5qyraiRRzFbG9yMBusz5bxmGdnGm1U97sTvslrSauvqt74Z9G09U4 -T1ekLb2K87H0nN+fznmzbSz98byoV3HO6fJ/IkU6s09Zqzh7kroJfF2WRbqs67KuD3V9qOv6UB9q -uq4P9aE+1GRh3NeH+lBTycEHAAAAAGBebG3PmD+CRGuvyboma7Im67Iu67KuyXq/fsk8L6ZZ5ouv -yZrzZft0tbu72zxdk1WprVjaeb/lna77EmM8XZPlNFMr52M5p6slnaxabZ6yWng+pbKnW9lPH8v2 -lk/6a7Jsle9fTRbFeUr3ln5Vt6cr4yprNVmX1raSzkrzlNRpNbqwzBXFFuNqsq6Vl4RH0zVZ75He -O611+VO+VxedbVEsc/b+v7i6s1Y8c66N39Jv2TH7bJk/D7ICH1HG4MtA0IUWu7CEiRSYyYfKZDYf -6kN9qA/1oSj9UBMo86E+VMjFhsf/5PDLGHAUGwgDNU1GwmkXpeNDkYCYRXwQgACUNjF/qImOD/Wh -BCAAAAAAAAAQgAC+/YM79owg8dK/VYIP9QD7OB/qQ30+1FSydHyo6cHztM2CiCQgZlHZzJxbevVq -rWyn9/5Tr/bGp/mf+qX3Nr71cVfRq8Xvbq+8fW3fntenv6Vv630qaxVtWyrt9Zzfs7034nopdbfW -L/1c++lPWX1an5nem7venj3txdaf9sw+L67VYlkvtrZ+U1wfu0tq7/23s5/S+RZLd5qzxCRcja7p -1fVyuk+fQmI7kDZt45JOrm3Gnq45kZzWz/1eb9c6cZUd31aM67zYfvtbbDGetzOdP63sefG/y2+K -u9ub/j/O8rqF8WVzvbIlZUKZO9txdu88kTqm9fn55u6+8HThKlp5c2VzbZe4wjiTiT+BMpOoI3ps -69Xkk20PQk/4YT6ZAvMR8KGmB9LXjTQoMFZ7P0RRJvq6UJYRdgYqcbKmK1+TVb2qpqvlrSbL3kpx -ptJWF6lKG726h4ldatCJvO7TTJqh1944r8V/q+jXqzi9in5vTxaxfbrTjI7oE9YRs8uKe9JMa+NZ -b52zVlorpXROV5x1InX/d/83plW83/8Tad7Zc7rP7qbdPaf7bO9bxZ7Tfdq+dtY5a513evX2I/1o -K0sztp1OW0VcRZqt21lFWk1X9CrSatvOSmm1NVOl2yppFW+1N3oVq63TFWsVbVXFOllEau2NNtp7 -pyvaKlpbXSzbyo4BOdu2b8nEDulEjw1eBAl1JhKp5JnEn0QymUycNnvLfmxxz+sTW7/z0nmt9Z6X -WjjR5p8V31sb17553u5r/Van0v0rnXk6/Vq/Lf6Zca2N/+tt63m2T0pv22zxdJtxxT9znljix7Xx -7Glnvd707XzsFk601qm19uL2bse5bZ1XNm57e2bqmVqf2VbPt1Jqczt274lntfe6xZPaO/GUTXO1 -/9aSiX4tnDjxz+yPOzv9TOvjib0tpU67Om07c5318bxtL7ZkYs4WTqw+cdNqv+18TDP+mXGef3tW -2TFfet0tmUinWzhx0vm1NraNK63zae1a/9L2mfFT2bZenOfEOXu9b7G99i2m73nKnhfj3DlPe/HT -x/jff+av/rji2S972llvxbj7K223NnvGF1dM215bc/ZsycS2cCKuPutb3NQb953Zvvtjt04pdu9a -KaaT+q0+Hdv2bjwzfZ/Uf3pTjO1b6vZzxtjepnNWSjN1SyZWauHEb5d9M8b4v+e99v68tXZtWiu9 -3W7JxP7cT2emuDs7pfVnxu32Z7WUWjjR0uuyadem0zO99m/709nzr+Ob76zUZs/zZs8ZY7dk4nT7 -b8lEv27JmNzqlkzM1s63lt7v9tn52kp7vuPpPW/nthNT6u50Ymsttvb7M72y/nx7a7VkIu3Guans -eJ/Wtj+vzZa+xXXm+e246Zy1Me2J8c/O2dLquc5qu7rF9Pbbv00tpteSiY7dwom3zr8vJ+6ulrZ/ -9jytpddaMhFnt3BiU/fH3U1rne49c7Z93Xp1XHGd3ZX+dcf2G3e1uXp22rRejF3O+RZO/PqWmbOk -9r/6z/fpNFdLJtrrFffLjtPKjln+tfnat7bWvzjfSm3tacnES53mz/J6N26//21xlh2zP77dcX53 -y84WTnRqcaVer//tf8/WZnw9Y79tO9ppyUT8Fk688+t8t9gzzvbnd8UUX/xe5/zsN8uOfu3Fsr/r -t83flVoyMU8LJ87slowJbfyf/9qWHem7pY/v1/v2Xr/ZM7butmZ7bVvH9q3Td9t+v7RlfFI7c+2v -2M6u+OKJMfbAqpVadzz71nf8s2bc2CuXZR/nP7vjat96/K1P66U9b622pSjLiBlOxoQkhG2ZyYR1 -HJiEOtMUgA5QJwvDbMM6Ik7ikykwlE8XDhJuJWyUaRKEXqyxQbdx4peFpYv511brjb9eSm21+D97 -z/k504pztt65+87Y8VIpPXZFxkCrAGFed2XoA0OXp5OBpU/DvAB8nci3hUDsyxhwG4jkw0Qx+7pR -lokiDvMcSETrXvdpotd9mvqfycRMZce3+O2M/iE46u7XKbsKuRGStpFEQqwjEmKd2FT2bdvUL842 -W8d96aWybWdMc6azZjur7Oy108gYaCG2ZRkhXJ4eYsMFKOIyL9N8WZiRME3zYRwgmHEirtSJhGgT -MSN1n4h1c5V+6+x5mzae99/93239TKm1TXNP29W/c559c9uJp61T9szYqzd+/9szY/9bLc23Wmwn -/fdJb8/2SufFfu+t2M6LX87P8/r0PB9Te+n/U9nx4lu/Xuq40oqv/EzrrfOpde+n3rnW2dP2dHpz -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 -+1eWTBWtP8oCC5SEQ3b3k1EWT7xB - - - diff --git a/docs/images/grid_example_result.png b/docs/images/grid_example_result.png new file mode 100644 index 00000000..12a8fb73 Binary files /dev/null and b/docs/images/grid_example_result.png differ diff --git a/docs/images/grid_example_schema.svg b/docs/images/grid_example_schema.svg new file mode 100644 index 00000000..3bf5aabf --- /dev/null +++ b/docs/images/grid_example_schema.svg @@ -0,0 +1,76 @@ + + + + +circle +line +show + + + + + + + + + + + + + + + + + + + + +grid + +nested commands + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/grid_example_zoom.svg b/docs/images/grid_example_zoom.svg new file mode 100644 index 00000000..f8f707be --- /dev/null +++ b/docs/images/grid_example_zoom.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + +grid + +nested commands + + + + + + + + + + + + + + + + + + + + + + + + +emptypipeline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ++ + +translateto celli, j + diff --git a/docs/images/repeat_example.png b/docs/images/repeat_example.png new file mode 100644 index 00000000..70a7f415 Binary files /dev/null and b/docs/images/repeat_example.png differ diff --git a/docs/reference.rst b/docs/reference.rst index 1daad239..223cfb3f 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -39,6 +39,18 @@ CLI reference .. click:: vpype_cli:end :prog: end +.. _cmd_eval: +.. click:: vpype_cli:eval_cmd + :prog: eval + +.. _cmd_forfile: +.. click:: vpype_cli:forfile + :prog: forfile + +.. _cmd_forlayer: +.. click:: vpype_cli:forlayer + :prog: forlayer + .. _cmd_frame: .. click:: vpype_cli:frame :prog: frame diff --git a/examples/grid.vpy b/examples/grid.vpy new file mode 100644 index 00000000..76c60d74 --- /dev/null +++ b/examples/grid.vpy @@ -0,0 +1,21 @@ +# Ask user for some information, using sensible defaults. +eval "files=glob(input('Files [*.svg]? ') or '*.svg')" # glob() creates a list of file based on a pattern +eval "cols=int(input('Number of columns [3]? ') or 3)" +eval "rows=ceil(len(files)/cols)" # the number of rows depends on the number of files +eval "col_width=convert_length(input('Column width [10cm]? ') or '10cm')" # convert_length() converts string like '3cm' to pixels +eval "row_height=convert_length(input('Row height [10cm]? ') or '10cm')" +eval "margin=convert_length(input('Margin [0.5cm]? ') or '0.5cm')" +eval "output_path=input('Output path [output.svg]? ') or 'output.svg'" + +# Create a grid with provided parameters. +grid -o %col_width% %row_height% %cols% %rows% + + # Read the `_i`-th file. The last row may be incomplete so we use an empty path and `--no-fail`. + read --no-fail "%files[_i] if _i < len(files) else ''%" + + # Layout the file in the cell. + layout -m %margin% %col_width%x%row_height% +end + +# wWrite the output file. +write "%output_path%" \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index ffe22160..c6e5721a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,6 +14,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "asteval" +version = "0.9.26" +description = "Safe, minimalistic evaluator of python expression using ast module" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +importlib_metadata = {version = "*", markers = "python_version < \"3.8\""} + [[package]] name = "atomicwrites" version = "1.4.0" @@ -88,7 +99,7 @@ python-versions = "*" [[package]] name = "charset-normalizer" -version = "2.0.11" +version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = true @@ -99,7 +110,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.3" +version = "8.0.4" description = "Composable command line interface toolkit" category = "main" optional = false @@ -130,7 +141,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "coverage" -version = "6.3" +version = "6.3.2" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -171,7 +182,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "fonttools" -version = "4.29.0" +version = "4.29.1" description = "Tools to manipulate font files" category = "main" optional = false @@ -224,7 +235,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.10.1" +version = "4.11.1" description = "Read metadata from Python packages" category = "main" optional = false @@ -237,7 +248,22 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] + +[[package]] +name = "importlib-resources" +version = "5.4.0" +description = "Read resources from Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] name = "iniconfig" @@ -266,7 +292,7 @@ name = "jinja2" version = "3.0.3" description = "A very fast and expressive template engine." category = "main" -optional = true +optional = false python-versions = ">=3.6" [package.dependencies] @@ -296,11 +322,11 @@ altgraph = ">=0.15" [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.0" description = "Safely add untrusted strings to HTML/XML markup." category = "main" -optional = true -python-versions = ">=3.6" +optional = false +python-versions = ">=3.7" [[package]] name = "matplotlib" @@ -417,7 +443,7 @@ python-versions = ">=3.7" [[package]] name = "platformdirs" -version = "2.4.1" +version = "2.5.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -479,7 +505,7 @@ python-versions = ">=3.5" [[package]] name = "pyinstaller" -version = "4.8" +version = "4.9" description = "PyInstaller bundles a Python application and all its dependencies into a single package." category = "dev" optional = false @@ -499,11 +525,11 @@ hook_testing = ["pytest (>=2.7.3)", "execnet (>=1.5.0)", "psutil"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2022.0" +version = "2022.2" description = "Community maintained hooks for PyInstaller" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7" [[package]] name = "pyparsing" @@ -529,7 +555,7 @@ shiboken2 = "5.15.2.1" [[package]] name = "pytest" -version = "6.2.5" +version = "7.0.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -544,10 +570,10 @@ iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" -toml = "*" +tomli = ">=1.0.0" [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-benchmark" @@ -583,14 +609,17 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale [[package]] name = "pytest-mpl" -version = "0.13" +version = "0.14.0" description = "pytest plugin to help with testing figures output from Matplotlib" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] +importlib-resources = {version = "*", markers = "python_version < \"3.8\""} +Jinja2 = "*" matplotlib = "*" +packaging = "*" pytest = "*" [package.extras] @@ -755,7 +784,7 @@ test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] name = "sphinx-autodoc-typehints" -version = "1.16.0" +version = "1.17.0" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" category = "main" optional = true @@ -770,7 +799,7 @@ type_comments = ["typed-ast (>=1.4.0)"] [[package]] name = "sphinx-click" -version = "3.0.3" +version = "3.1.0" description = "Sphinx extension that automatically documents click applications" category = "main" optional = true @@ -869,7 +898,7 @@ test = ["pytest"] [[package]] name = "svgelements" -version = "1.6.7" +version = "1.6.9" description = "Svg Elements Parsing" category = "main" optional = false @@ -883,17 +912,9 @@ category = "main" optional = false python-versions = ">=3.6" -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - [[package]] name = "tomli" -version = "2.0.0" +version = "2.0.1" description = "A lil' TOML parser" category = "main" optional = false @@ -925,7 +946,7 @@ python-versions = "*" [[package]] name = "types-toml" -version = "0.10.3" +version = "0.10.4" description = "Typing stubs for toml" category = "dev" optional = false @@ -933,7 +954,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "4.0.1" +version = "4.1.1" description = "Backported and Experimental Type Hints for Python 3.6+" category = "main" optional = false @@ -971,7 +992,7 @@ docs = ["Sphinx", "sphinx-click", "sphinx-autodoc-typehints", "sphinx-rtd-theme" [metadata] lock-version = "1.1" python-versions = ">=3.7, !=3.9.0, <3.10" -content-hash = "2fa46d0e62f91bca2efc3feb3a5aca3a29e23675a2b8b50aa71b14c415d61d13" +content-hash = "e03af9957e8aae66b123e7c75865a994d87278fad7ab902ee499e78e52232dbc" [metadata.files] alabaster = [ @@ -982,6 +1003,9 @@ altgraph = [ {file = "altgraph-0.17.2-py2.py3-none-any.whl", hash = "sha256:743628f2ac6a7c26f5d9223c91ed8ecbba535f506f4b6f558885a8a56a105857"}, {file = "altgraph-0.17.2.tar.gz", hash = "sha256:ebf2269361b47d97b3b88e696439f6e4cbc607c17c51feb1754f90fb79839158"}, ] +asteval = [ + {file = "asteval-0.9.26.tar.gz", hash = "sha256:36125613ec21ed3e33e370ca8960a1f1e8a2324d78a8016bfa5ad76f1e16ef05"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -1028,12 +1052,12 @@ certifi = [ {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.11.tar.gz", hash = "sha256:98398a9d69ee80548c762ba991a4728bfc3836768ed226b3945908d1a688371c"}, - {file = "charset_normalizer-2.0.11-py3-none-any.whl", hash = "sha256:2842d8f5e82a1f6aa437380934d5e1cd4fcf2003b06fed6940769c164a480a45"}, + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, + {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, + {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, @@ -1044,50 +1068,47 @@ commonmark = [ {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ - {file = "coverage-6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8071e7d9ba9f457fc674afc3de054450be2c9b195c470147fbbc082468d8ff7"}, - {file = "coverage-6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86c91c511853dfda81c2cf2360502cb72783f4b7cebabef27869f00cbe1db07d"}, - {file = "coverage-6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4ce3b647bd1792d4394f5690d9df6dc035b00bcdbc5595099c01282a59ae01"}, - {file = "coverage-6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a491e159294d756e7fc8462f98175e2d2225e4dbe062cca7d3e0d5a75ba6260"}, - {file = "coverage-6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d008e0f67ac800b0ca04d7914b8501312c8c6c00ad8c7ba17754609fae1231a"}, - {file = "coverage-6.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4578728c36de2801c1deb1c6b760d31883e62e33f33c7ba8f982e609dc95167d"}, - {file = "coverage-6.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7ee317486593193e066fc5e98ac0ce712178c21529a85c07b7cb978171f25d53"}, - {file = "coverage-6.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2bc85664b06ba42d14bb74d6ddf19d8bfc520cb660561d2d9ce5786ae72f71b5"}, - {file = "coverage-6.3-cp310-cp310-win32.whl", hash = "sha256:27a94db5dc098c25048b0aca155f5fac674f2cf1b1736c5272ba28ead2fc267e"}, - {file = "coverage-6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bde4aeabc0d1b2e52c4036c54440b1ad05beeca8113f47aceb4998bb7471e2c2"}, - {file = "coverage-6.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:509c68c3e2015022aeda03b003dd68fa19987cdcf64e9d4edc98db41cfc45d30"}, - {file = "coverage-6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e4ff163602c5c77e7bb4ea81ba5d3b793b4419f8acd296aae149370902cf4e92"}, - {file = "coverage-6.3-cp311-cp311-win_amd64.whl", hash = "sha256:d1675db48490e5fa0b300f6329ecb8a9a37c29b9ab64fa9c964d34111788ca2d"}, - {file = "coverage-6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7eed8459a2b81848cafb3280b39d7d49950d5f98e403677941c752e7e7ee47cb"}, - {file = "coverage-6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b4285fde5286b946835a1a53bba3ad41ef74285ba9e8013e14b5ea93deaeafc"}, - {file = "coverage-6.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4748349734110fd32d46ff8897b561e6300d8989a494ad5a0a2e4f0ca974fc7"}, - {file = "coverage-6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:823f9325283dc9565ba0aa2d240471a93ca8999861779b2b6c7aded45b58ee0f"}, - {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fff16a30fdf57b214778eff86391301c4509e327a65b877862f7c929f10a4253"}, - {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:da1a428bdbe71f9a8c270c7baab29e9552ac9d0e0cba5e7e9a4c9ee6465d258d"}, - {file = "coverage-6.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7d82c610a2e10372e128023c5baf9ce3d270f3029fe7274ff5bc2897c68f1318"}, - {file = "coverage-6.3-cp37-cp37m-win32.whl", hash = "sha256:11e61c5548ecf74ea1f8b059730b049871f0e32b74f88bd0d670c20c819ad749"}, - {file = "coverage-6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0c3525b1a182c8ffc9bca7e56b521e0c2b8b3e82f033c8e16d6d721f1b54d6"}, - {file = "coverage-6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a189036c50dcd56100746139a459f0d27540fef95b09aba03e786540b8feaa5f"}, - {file = "coverage-6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32168001f33025fd756884d56d01adebb34e6c8c0b3395ca8584cdcee9c7c9d2"}, - {file = "coverage-6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5d79c9af3f410a2b5acad91258b4ae179ee9c83897eb9de69151b179b0227f5"}, - {file = "coverage-6.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85c5fc9029043cf8b07f73fbb0a7ab6d3b717510c3b5642b77058ea55d7cacde"}, - {file = "coverage-6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7596aa2f2b8fa5604129cfc9a27ad9beec0a96f18078cb424d029fdd707468d"}, - {file = "coverage-6.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce443a3e6df90d692c38762f108fc4c88314bf477689f04de76b3f252e7a351c"}, - {file = "coverage-6.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:012157499ec4f135fc36cd2177e3d1a1840af9b236cbe80e9a5ccfc83d912a69"}, - {file = "coverage-6.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a34d313105cdd0d3644c56df2d743fe467270d6ab93b5d4a347eb9fec8924d6"}, - {file = "coverage-6.3-cp38-cp38-win32.whl", hash = "sha256:6e78b1e25e5c5695dea012be473e442f7094d066925604be20b30713dbd47f89"}, - {file = "coverage-6.3-cp38-cp38-win_amd64.whl", hash = "sha256:433b99f7b0613bdcdc0b00cc3d39ed6d756797e3b078d2c43f8a38288520aec6"}, - {file = "coverage-6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ed3244b415725f08ca3bdf02ed681089fd95e9465099a21c8e2d9c5d6ca2606"}, - {file = "coverage-6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab4fc4b866b279740e0d917402f0e9a08683e002f43fa408e9655818ed392196"}, - {file = "coverage-6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8582e9280f8d0f38114fe95a92ae8d0790b56b099d728cc4f8a2e14b1c4a18c"}, - {file = "coverage-6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c72bb4679283c6737f452eeb9b2a0e570acaef2197ad255fb20162adc80bea76"}, - {file = "coverage-6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca29c352389ea27a24c79acd117abdd8a865c6eb01576b6f0990cd9a4e9c9f48"}, - {file = "coverage-6.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:152cc2624381df4e4e604e21bd8e95eb8059535f7b768c1fb8b8ae0b26f47ab0"}, - {file = "coverage-6.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:51372e24b1f7143ee2df6b45cff6a721f3abe93b1e506196f3ffa4155c2497f7"}, - {file = "coverage-6.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72d9d186508325a456475dd05b1756f9a204c7086b07fffb227ef8cee03b1dc2"}, - {file = "coverage-6.3-cp39-cp39-win32.whl", hash = "sha256:649df3641eb351cdfd0d5533c92fc9df507b6b2bf48a7ef8c71ab63cbc7b5c3c"}, - {file = "coverage-6.3-cp39-cp39-win_amd64.whl", hash = "sha256:e67ccd53da5958ea1ec833a160b96357f90859c220a00150de011b787c27b98d"}, - {file = "coverage-6.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:27ac7cb84538e278e07569ceaaa6f807a029dc194b1c819a9820b9bb5dbf63ab"}, - {file = "coverage-6.3.tar.gz", hash = "sha256:987a84ff98a309994ca77ed3cc4b92424f824278e48e4bf7d1bb79a63cfe2099"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, + {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, + {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, + {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, + {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, + {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, + {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, + {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, + {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, + {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, + {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, + {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, ] cycler = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, @@ -1102,8 +1123,8 @@ docutils = [ {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] fonttools = [ - {file = "fonttools-4.29.0-py3-none-any.whl", hash = "sha256:ed9496e5650b977a697c50ac99c8e8331f9eae3f99e5ae649623359103306dfe"}, - {file = "fonttools-4.29.0.zip", hash = "sha256:f4834250db2c9855c3385459579dbb5cdf74349ab059ea0e619359b65ae72037"}, + {file = "fonttools-4.29.1-py3-none-any.whl", hash = "sha256:1933415e0fbdf068815cb1baaa1f159e17830215f7e8624e5731122761627557"}, + {file = "fonttools-4.29.1.zip", hash = "sha256:2b18a172120e32128a80efee04cff487d5d140fe7d817deb648b2eee023a40e4"}, ] future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, @@ -1141,8 +1162,12 @@ imagesize = [ {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"}, - {file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"}, + {file = "importlib_metadata-4.11.1-py3-none-any.whl", hash = "sha256:e0bc84ff355328a4adfc5240c4f211e0ab386f80aa640d1b11f0618a1d282094"}, + {file = "importlib_metadata-4.11.1.tar.gz", hash = "sha256:175f4ee440a0317f6e8d81b7f8d4869f93316170a65ad2b007d2929186c8052c"}, +] +importlib-resources = [ + {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, + {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1207,75 +1232,46 @@ macholib = [ {file = "macholib-1.15.2.tar.gz", hash = "sha256:1542c41da3600509f91c165cb897e7e54c0e74008bd8da5da7ebbee519d593d2"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-win32.whl", hash = "sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454"}, + {file = "MarkupSafe-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-win32.whl", hash = "sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a"}, + {file = "MarkupSafe-2.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-win32.whl", hash = "sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8"}, + {file = "MarkupSafe-2.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-win32.whl", hash = "sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05"}, + {file = "MarkupSafe-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7"}, + {file = "MarkupSafe-2.1.0.tar.gz", hash = "sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f"}, ] matplotlib = [ {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b"}, @@ -1462,8 +1458,8 @@ pillow = [ {file = "Pillow-9.0.0.tar.gz", hash = "sha256:ee6e2963e92762923956fe5d3479b1fdc3b76c83f290aad131a2f98c3df0593e"}, ] platformdirs = [ - {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, - {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, + {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, + {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, @@ -1485,21 +1481,21 @@ pygments = [ {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, ] pyinstaller = [ - {file = "pyinstaller-4.8-py3-none-macosx_10_13_universal2.whl", hash = "sha256:b0b3a31aa60292469f9595f298e2c147cba29c30edcd92a38fdce27727809625"}, - {file = "pyinstaller-4.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9fbb05f5f67862005234da8c7eac69ef87e086f90e345749260051b031774c52"}, - {file = "pyinstaller-4.8-py3-none-manylinux2014_i686.whl", hash = "sha256:15d9266d78dc757c103962826e62bce1513825078160be580534ead2ef53087c"}, - {file = "pyinstaller-4.8-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:5c2fd5f18c0397f3d9160446035556afc7f6446fd88048887fdf46eadf85c5ec"}, - {file = "pyinstaller-4.8-py3-none-manylinux2014_s390x.whl", hash = "sha256:6f5cdc39fbdec7b2e0c46cc0f5bd0071bb85e592e324bf4e15375c5ff19e55fc"}, - {file = "pyinstaller-4.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:4c848720a65a5bd41249bc804d1bd3dd089bb56aef7f1c5e11f774f11e649443"}, - {file = "pyinstaller-4.8-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:44783d58ac4cb0a74a4f2180da4dacbe6a7a013a62b3aa10be6082252e296954"}, - {file = "pyinstaller-4.8-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b720853a00bd9547b7d6403d85f23b7f7e451e41bc907673d9fc7f8d9d274594"}, - {file = "pyinstaller-4.8-py3-none-win32.whl", hash = "sha256:53ed05214dd67624756fe4e82e861857921a79d0392debf8c9f5bb0ba5a479b6"}, - {file = "pyinstaller-4.8-py3-none-win_amd64.whl", hash = "sha256:f00e1296abac71f3b5bb9fdc2e0d4c079201d62faeeeb894ccadd0616179fee3"}, - {file = "pyinstaller-4.8.tar.gz", hash = "sha256:7ae868bbcc502832a2c802c84a1dbb9f48b44445c50144c29bfcd7b760140e13"}, + {file = "pyinstaller-4.9-py3-none-macosx_10_13_universal2.whl", hash = "sha256:e2f165cea4470ce8a8349112cd78f48a61413805adc17792a91997a11cfe1d80"}, + {file = "pyinstaller-4.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:24035eb9fffa2e3e288b4c1c9710043819efc7203cae5c8c573bec16f4a8e98f"}, + {file = "pyinstaller-4.9-py3-none-manylinux2014_i686.whl", hash = "sha256:a0b988cfc197d40e3d773b3aa1c7d3e918fc0933b4c15ec3fc5d156f222d82cb"}, + {file = "pyinstaller-4.9-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:62c97cbbdbee30974d607eb1de9afb081eb3adba787c203b00438e21027b829b"}, + {file = "pyinstaller-4.9-py3-none-manylinux2014_s390x.whl", hash = "sha256:7f46ab11ec986e4c525b93251063144e12d432a132dbc0070e3030e34c76537a"}, + {file = "pyinstaller-4.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:b5f1a94150315ea75bf3501be6c8476d65a7209580bb662da06dbdbc4454f375"}, + {file = "pyinstaller-4.9-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:ebeb87cdbadb2b4e8f991ffd9945ebd4fb3a7303180e63682c3e1ce01b3fdd22"}, + {file = "pyinstaller-4.9-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:59372b950d176fdc5ecea29719a8ab3f194b73a15b7f9875ac2a1de9a3daf5ed"}, + {file = "pyinstaller-4.9-py3-none-win32.whl", hash = "sha256:ec3ca331d565ffca1b6470c5aaf798885a03708c3d0b15c1b19009126f84c1d4"}, + {file = "pyinstaller-4.9-py3-none-win_amd64.whl", hash = "sha256:bec57b3b2b6178907255557ec0fc4b5ce5a0474013414cdadea853205c74ed26"}, + {file = "pyinstaller-4.9.tar.gz", hash = "sha256:75a180a658871bc41f9cf94b6f90ffa54e98f5d6a7cdb02d7530f0360afe24f9"}, ] pyinstaller-hooks-contrib = [ - {file = "pyinstaller-hooks-contrib-2022.0.tar.gz", hash = "sha256:61b667f51b2525377fae30793f38fd9752a08032c72b209effabf707c840cc38"}, - {file = "pyinstaller_hooks_contrib-2022.0-py2.py3-none-any.whl", hash = "sha256:29f0bd8fbb2ff6f2df60a0c147e5b5ad65ae5c1a982d90641a5f712de03fa161"}, + {file = "pyinstaller-hooks-contrib-2022.2.tar.gz", hash = "sha256:ab1d14fe053016fff7b0c6aea51d980bac6d02114b04063b46ef7dac70c70e1e"}, + {file = "pyinstaller_hooks_contrib-2022.2-py2.py3-none-any.whl", hash = "sha256:7605e440ccb55904cb2a87d72e83642ef176fb7030c77e52ac4d9679bb3d1537"}, ] pyparsing = [ {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, @@ -1514,8 +1510,8 @@ pyside2 = [ {file = "PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-none-win_amd64.whl", hash = "sha256:af6b263fe63ba6dea7eaebae80aa7b291491fe66f4f0057c0aafe780cc83da9d"}, ] pytest = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, + {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, ] pytest-benchmark = [ {file = "pytest-benchmark-3.4.1.tar.gz", hash = "sha256:40e263f912de5a81d891619032983557d62a3d85843f9a9f30b98baea0cd7b47"}, @@ -1526,8 +1522,8 @@ pytest-cov = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] pytest-mpl = [ - {file = "pytest-mpl-0.13.tar.gz", hash = "sha256:582db6e14315f9b08cbd2df39b136dc344bfe8a27c2f05b995460fb0969ec19e"}, - {file = "pytest_mpl-0.13-py3-none-any.whl", hash = "sha256:fc41ef335af17d15fd7f1ecf6d9549a64c3ad9fb2a27b2ad4177fe608449ff24"}, + {file = "pytest-mpl-0.14.0.tar.gz", hash = "sha256:884e078d2d5380af5643384e233c358e9659825fb2d97ffdaf8f185c434c8d89"}, + {file = "pytest_mpl-0.14.0-py3-none-any.whl", hash = "sha256:6997c338b8a3fe810ea37c63f1f72b8a0ffa06a8cdf6ebe45a1078396e577464"}, ] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, @@ -1625,12 +1621,12 @@ sphinx = [ {file = "Sphinx-4.4.0.tar.gz", hash = "sha256:6caad9786055cb1fa22b4a365c1775816b876f91966481765d7d50e9f0dd35cc"}, ] sphinx-autodoc-typehints = [ - {file = "sphinx_autodoc_typehints-1.16.0-py3-none-any.whl", hash = "sha256:b5efe1fb5754349f849ca09b1f5c9b4bb37f1e360f00fbde003b12c60d67cc3a"}, - {file = "sphinx_autodoc_typehints-1.16.0.tar.gz", hash = "sha256:21df6ee692c2c8366f6df13b13e4d4ab8af25cc0dfb65e2d182351528b6eb704"}, + {file = "sphinx_autodoc_typehints-1.17.0-py3-none-any.whl", hash = "sha256:081daf53077b4ae1c28347d6d858e13e63aefe3b4aacef79fd717dd60687b470"}, + {file = "sphinx_autodoc_typehints-1.17.0.tar.gz", hash = "sha256:51c7b3f5cb9ccd15d0b52088c62df3094f1abd9612930340365c26def8629a14"}, ] sphinx-click = [ - {file = "sphinx-click-3.0.3.tar.gz", hash = "sha256:1ea30b53e06b14088e6343d200cdabe5e50304311eb281234768073b49135d8e"}, - {file = "sphinx_click-3.0.3-py3-none-any.whl", hash = "sha256:6003bb8ce697e3512ce45f02c91b3ef8e6a1df50b6abfc0e95add9026f47dfde"}, + {file = "sphinx-click-3.1.0.tar.gz", hash = "sha256:36dbf271b1d2600fb05bd598ddeed0b6b6acf35beaf8bc9d507ba7716b232b0e"}, + {file = "sphinx_click-3.1.0-py3-none-any.whl", hash = "sha256:8fb0b048a577d346d741782e44d041d7e908922858273d99746f305870116121"}, ] sphinx-rtd-theme = [ {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, @@ -1661,20 +1657,16 @@ sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] svgelements = [ - {file = "svgelements-1.6.7-py2.py3-none-any.whl", hash = "sha256:7b10c45dd39abf82fd72133f8fd53305476f409d30d93851e57e8bc1b403a6a8"}, - {file = "svgelements-1.6.7.tar.gz", hash = "sha256:cf9c5e670de05ac3d2ae7c7a7b7fde82d5456a1508182597098d0ded23f86ddf"}, + {file = "svgelements-1.6.9-py2.py3-none-any.whl", hash = "sha256:83c3e53d7ae4cd7f4d7f4e7be29444870507e0d559a7a06160284be9e222c325"}, + {file = "svgelements-1.6.9.tar.gz", hash = "sha256:355a5cd5f43834cfdfab669298253d17138c76b00feafb53fdbb59000aeb54a7"}, ] svgwrite = [ {file = "svgwrite-1.4.1-py3-none-any.whl", hash = "sha256:4b21652a1d9c543a6bf4f9f2a54146b214519b7540ca60cb99968ad09ef631d0"}, {file = "svgwrite-1.4.1.zip", hash = "sha256:e220a4bf189e7e214a55e8a11421d152b5b6fb1dd660c86a8b6b61fe8cc2ac48"}, ] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] tomli = [ - {file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"}, - {file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typed-ast = [ {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, @@ -1711,12 +1703,12 @@ types-pkg-resources = [ {file = "types_pkg_resources-0.1.3-py2.py3-none-any.whl", hash = "sha256:0cb9972cee992249f93fff1a491bf2dc3ce674e5a1926e27d4f0866f7d9b6d9c"}, ] types-toml = [ - {file = "types-toml-0.10.3.tar.gz", hash = "sha256:215a7a79198651ec5bdfd66193c1e71eb681a42f3ef7226c9af3123ced62564a"}, - {file = "types_toml-0.10.3-py3-none-any.whl", hash = "sha256:988457744d9774d194e3539388772e3a685d8057b7c4a89407afeb0a6cbd1b14"}, + {file = "types-toml-0.10.4.tar.gz", hash = "sha256:9340e7c1587715581bb13905b3af30b79fe68afaccfca377665d5e63b694129a"}, + {file = "types_toml-0.10.4-py3-none-any.whl", hash = "sha256:4a9ffd47bbcec49c6fde6351a889b2c1bd3c0ef309fa0eed60dc28e58c8b9ea6"}, ] typing-extensions = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, + {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, + {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] urllib3 = [ {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, diff --git a/pyproject.toml b/pyproject.toml index a17c3d99..e8bdacb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,18 +39,19 @@ click = "~8.0.1" multiprocess = "^0.70.11" numpy = ">=1.20" pnoise = "^0.1.0" -Shapely = {extras = ["vectorized"], version = ">=1.7.1,<1.9.0"} +Shapely = {extras = ["vectorized"], version = "1.8.0"} # 1.8.1 breaks win installer scipy = "^1.6" setuptools = "^51.0.0" -svgelements = "1.6.7" +svgelements = "1.6.9" svgwrite = "~1.4" tomli = "^2.0.0" +asteval = "^0.9.26" # additional dependencies for the viewer and the `show` command matplotlib = { version = ">=3.3.2,<3.6.0", optional = true } glcontext = { version = ">=2.3.2", optional = true } # 2.3.2 needed to fix #200 moderngl = { version = "^5.6.2", optional = true } -Pillow = { version = ">=9.0.0", optional = true } +Pillow = { version = ">=9.0.0,!=9.0.1", optional = true } # 9.0.1 doesn't work on M1 PySide2 = { version = "^5.15.2", optional = true } # these needs to be there because of https://github.com/python-poetry/poetry/issues/1145 diff --git a/tests/conftest.py b/tests/conftest.py index d86eb8b7..f88de981 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,12 @@ +import contextlib +import difflib +import hashlib import os import pathlib -from typing import Callable +import sys +from typing import Callable, List +from xml.dom import minidom +from xml.etree import ElementTree import numpy as np import pytest @@ -56,6 +62,12 @@ def pytest_addoption(parser): help="Skip tests using assert_image_similarity().", ) + parser.addoption( + "--store-ref-svg", + action="store_true", + help="Write reference SVGs for reference_svg().", + ) + def write_image_similarity_fail_report( image: Image, @@ -109,7 +121,7 @@ def _assert_image_similarity(img: Image) -> None: if sum_sq_diff != 0: normalized_sum_sq_diff = sum_sq_diff / np.sqrt(sum_sq_diff) - if normalized_sum_sq_diff > 5.5: # pragma: no cover + if normalized_sum_sq_diff > 6.5: # pragma: no cover write_image_similarity_fail_report( img, ref_img, img_arr, ref_img_arr, test_id, normalized_sum_sq_diff ) @@ -118,3 +130,64 @@ def _assert_image_similarity(img: Image) -> None: ) return _assert_image_similarity + + +def _read_SVG_lines(path: pathlib.Path) -> List[str]: + tree = ElementTree.parse(path) + xml_str = ElementTree.tostring(tree.getroot()) + # ET.canonicalize doesn't exist on Python 3.7 + canon = ElementTree.canonicalize(xml_str, strip_text=True) # type: ignore + lines = minidom.parseString(canon).toprettyxml().splitlines() + return [line for line in lines if " Callable: + """Compare a SVG output to a saved reference. + + Use `--store-ref-svg` to save reference SVGs. + + Example:: + + def test_ref_svg(reference_svg): + with reference_svg() as path: + export_svg_to(path) + """ + + if sys.version_info < (3, 8): # pragma: no cover + pytest.skip("requires Python 3.8 or higher") + + store_ref_svg = request.config.getoption("--store-ref-svg") + test_id = "refsvg_" + hashlib.md5(request.node.name.encode()).hexdigest() + ".svg" + ref_path = pathlib.Path(REFERENCE_IMAGES_DIR) / test_id + temp_file = tmp_path / test_id + + @contextlib.contextmanager + def _reference_svg(): + nonlocal ref_path, temp_file, store_ref_svg + + yield temp_file + + if store_ref_svg: # pragma: no cover + ref_path.write_bytes(temp_file.read_bytes()) + else: + if not ref_path.exists(): # pragma: no cover + pytest.fail(f"reference SVG does not exist") + + temp_lines = _read_SVG_lines(temp_file) + ref_lines = _read_SVG_lines(ref_path) + + if len(temp_lines) != len(ref_lines) or not all( + a == b for a, b in zip(temp_lines, ref_lines) + ): + delta = difflib.unified_diff( + temp_lines, + ref_lines, + fromfile="", + tofile=str(ref_path.relative_to(pathlib.Path(REFERENCE_IMAGES_DIR))), + lineterm="", + ) + + pytest.fail(f"generated SVG does not match reference:\n" + "\n".join(delta)) + + return _reference_svg diff --git a/tests/data/baseline/refsvg_02b3cc3b0619d7e1e8c03a969e95df3e.svg b/tests/data/baseline/refsvg_02b3cc3b0619d7e1e8c03a969e95df3e.svg new file mode 100644 index 00000000..20ffd6b2 --- /dev/null +++ b/tests/data/baseline/refsvg_02b3cc3b0619d7e1e8c03a969e95df3e.svg @@ -0,0 +1,17 @@ + + + + + + image/svg+xml + vpype -k test_reference_output --store-ref-svg + + 2022-02-14T17:02:36.161253 + + + + + + + + diff --git a/tests/data/baseline/refsvg_1c5a4f29601c309ce43dfe702529517b.svg b/tests/data/baseline/refsvg_1c5a4f29601c309ce43dfe702529517b.svg new file mode 100644 index 00000000..b60efbf9 --- /dev/null +++ b/tests/data/baseline/refsvg_1c5a4f29601c309ce43dfe702529517b.svg @@ -0,0 +1,30 @@ + + + + + + image/svg+xml + vpype -k test_reference_output --store-ref-svg + + 2022-02-14T16:42:20.700491 + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/baseline/refsvg_a4fc2c104911dd17ae029aacaf30949f.svg b/tests/data/baseline/refsvg_a4fc2c104911dd17ae029aacaf30949f.svg new file mode 100644 index 00000000..1cbd2cda --- /dev/null +++ b/tests/data/baseline/refsvg_a4fc2c104911dd17ae029aacaf30949f.svg @@ -0,0 +1,17 @@ + + + + + + image/svg+xml + vpype -k test_reference_output --store-ref-svg + + 2022-02-14T16:42:20.681548 + + + + + + + + diff --git a/tests/data/baseline/test_show--begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_show--begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 4529571f..72365db5 100644 Binary files a/tests/data/baseline/test_show--begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_show--begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_show--c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_show--c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 72549dae..7f5a210e 100644 Binary files a/tests/data/baseline/test_show--c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_show--c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_show--d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_show--d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index ed8a1bd1..d9f1f867 100644 Binary files a/tests/data/baseline/test_show--d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_show--d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_show--o-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_show--o-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index a9eee103..43dee394 100644 Binary files a/tests/data/baseline/test_show--o-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_show--o-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_show--p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_show--p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index b436aff7..e774013b 100644 Binary files a/tests/data/baseline/test_show--p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_show--p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-ag -u cm-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-ag -u cm-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 55aa5a48..4af969a2 100644 Binary files a/tests/data/baseline/test_showmpl_-ag -u cm-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-ag -u cm-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-ag-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-ag-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 1b6fa9d5..8797cd51 100644 Binary files a/tests/data/baseline/test_showmpl_-ag-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-ag-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-ah-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-ah-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 8de1c05d..903c0a06 100644 Binary files a/tests/data/baseline/test_showmpl_-ah-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-ah-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index 52862e28..7811c75a 100644 Binary files a/tests/data/baseline/test_showmpl_-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index d9cde91f..68acdb2f 100644 Binary files a/tests/data/baseline/test_showmpl_-c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-c-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index fc33881b..f0f1add4 100644 Binary files a/tests/data/baseline/test_showmpl_-d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-d-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-h-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-h-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index ba202dbb..65e23fa7 100644 Binary files a/tests/data/baseline/test_showmpl_-h-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-h-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/data/baseline/test_showmpl_-p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png b/tests/data/baseline/test_showmpl_-p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png index dad4c8f0..911a7696 100644 Binary files a/tests/data/baseline/test_showmpl_-p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png and b/tests/data/baseline/test_showmpl_-p-begin grid -o 3cm 3cm 5 5 circle 0 0 5cm end.png differ diff --git a/tests/test_commands.py b/tests/test_commands.py index 149d9dd7..233907ef 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -5,6 +5,7 @@ import pytest import vpype as vp +import vpype_cli from vpype_cli import DebugData, cli, execute, global_processor from .utils import TESTS_DIRECTORY, execute_single_line @@ -12,6 +13,7 @@ CM = 96 / 2.54 EXAMPLE_SVG = TESTS_DIRECTORY / "data" / "test_svg" / "svg_width_height" / "percent_size.svg" +EXAMPLE_SVG_DIR = TESTS_DIRECTORY / "data" / "test_svg" / "misc" @dataclass @@ -21,13 +23,15 @@ class Command: exit_code_one_layer: int = 0 exit_code_two_layers: int = 0 preserves_metadata: bool = True + keeps_page_size: bool = True MINIMAL_COMMANDS = [ - Command("begin grid 2 2 line 0 0 10 10 end"), + Command("begin grid 2 2 line 0 0 10 10 end", keeps_page_size=False), + Command("begin grid 0 0 line 0 0 10 10 end"), # doesn't update page size Command("begin repeat 2 line 0 0 10 10 end"), - Command("grid 2 2 line 0 0 10 10 end"), # implicit `begin` - Command("grid 2 2 repeat 2 random -n 1 end end"), # nested block + Command("grid 2 2 line 0 0 10 10 end", keeps_page_size=False), # implicit `begin` + Command("grid 2 2 repeat 2 random -n 1 end end", keeps_page_size=False), # nested block Command("frame"), Command("random"), Command("line 0 0 1 1"), @@ -48,6 +52,7 @@ class Command: Command("crop 0 0 1 1"), Command("linesort"), Command("linesort --two-opt"), + Command("random linesort"), # make sure there is something sort Command("linemerge"), Command("linesimplify"), Command("multipass"), @@ -68,11 +73,11 @@ class Command: Command("trim 1mm 1mm"), Command("splitall"), Command("filter --min-length 1mm"), - Command("pagesize 10inx15in"), + Command("pagesize 10inx15in", keeps_page_size=False), Command("stat"), Command("snap 1"), Command("reverse"), - Command("layout a4"), + Command("layout a4", keeps_page_size=False), Command("squiggles"), Command("text 'hello wold'"), Command("penwidth 0.15mm", preserves_metadata=False), @@ -86,8 +91,13 @@ class Command: Command("proplist -l 1"), Command("propdel -g prop:global", preserves_metadata=False), Command("propdel -l 1 prop:layer", preserves_metadata=False), - Command("propclear -g", preserves_metadata=False), + Command("propclear -g", preserves_metadata=False, keeps_page_size=False), Command("propclear -l 1", preserves_metadata=False), + Command( + f"forfile '{EXAMPLE_SVG_DIR / '*.svg'}' text -p 0 %_i*cm% '%_i%/%_n%: %_name%' end" + ), + Command("eval x=2 eval %y=3 eval z=4% eval %w=5%"), + Command("forlayer text '%_lid% (%_i%/%_n%): %_name%' end"), ] # noinspection SpellCheckingInspection @@ -146,7 +156,7 @@ def test_commands_keeps_page_size(runner, cmd): args = cmd.command - if args.split()[0] in ["pagesize", "layout"] or args.startswith("propclear -g"): + if not cmd.keeps_page_size: pytest.skip(f"command {args.split()[0]} fail this test by design") page_size = None @@ -661,3 +671,19 @@ def test_property_commands(runner, cmd, expected_output): res = runner.invoke(cli, cmd) assert res.exit_code == 0 assert res.stdout.strip() == expected_output.strip() + + +def test_forlayer_command_property_accessor(): + doc = vpype_cli.execute( + "pens rgb forlayer eval '_prop.test=_i;_prop.test2=_prop.test' end" + ) + for i in range(3): + assert doc.layers[i + 1].property("test") == i + assert doc.layers[i + 1].property("test2") == i + + doc = vpype_cli.execute( + 'pens rgb forlayer eval \'_prop["test"]=_i;_prop["test2"]=_prop["test"]\' end' + ) + for i in range(3): + assert doc.layers[i + 1].property("test") == i + assert doc.layers[i + 1].property("test2") == i diff --git a/tests/test_files.py b/tests/test_files.py index d809a6cf..68ae57a9 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -1,9 +1,11 @@ """Run a bunch of tests on the svg collection.""" import difflib +import io import os import re from typing import Set +import click import numpy as np import pytest @@ -388,7 +390,7 @@ def _prop_set(document: vp.Document, prop: str) -> Set: def test_read_layer_assumes_single_layer(caplog): test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" - doc = vpype_cli.execute(f"read --layer 2 '{test_file}'", global_opt="-v") + doc = vpype_cli.execute(f"read --layer 2 '{test_file}'", global_opt="-vv") assert "assuming single-layer mode" in caplog.text assert len(doc.layers) == 1 @@ -423,3 +425,59 @@ def test_write_svg_svg_props_unknown_namespace(capsys): "line 0 0 10 10 layout a5 propset -g svg_unknown_version '1.1.0' write -r -f svg -" ) assert 'unknown:version="1.1.0"' not in capsys.readouterr().out + + +def test_read_no_fail(): + with pytest.raises(click.BadParameter): + vpype_cli.execute("read doesnotexist.svg") + vpype_cli.execute("read --no-fail doesnotexist.svg") + + +def test_read_sets_source_properties(): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + doc = vpype_cli.execute(f"read '{test_file}'") + assert doc.property(vp.METADATA_FIELD_SOURCE) == test_file + assert doc.property(vp.METADATA_FIELD_SOURCE_LIST) == (test_file,) + + +def test_read_by_attrs_sets_source_properties(): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + doc = vpype_cli.execute(f"read -a fill -a stroke '{test_file}'") + assert doc.property(vp.METADATA_FIELD_SOURCE) == test_file + assert doc.property(vp.METADATA_FIELD_SOURCE_LIST) == (test_file,) + + +def test_read_single_layer_sets_source_properties(): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + doc = vpype_cli.execute(f"read --layer 1 '{test_file}'") + assert doc.property(vp.METADATA_FIELD_SOURCE_LIST) == (test_file,) + assert len(doc.layers) == 1 + assert doc.layers[1].property(vp.METADATA_FIELD_SOURCE) == test_file + + +def test_read_stdin_sets_source_properties(monkeypatch): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + monkeypatch.setattr("sys.stdin", io.StringIO(test_file.read_text())) + + doc = vpype_cli.execute(f"read -") + assert vp.METADATA_FIELD_SOURCE not in doc.metadata + assert doc.sources == tuple() + + +def test_read_single_layer_stdin_sets_source_properties(monkeypatch): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + monkeypatch.setattr("sys.stdin", io.StringIO(test_file.read_text())) + + doc = vpype_cli.execute(f"read -l1 -") + assert vp.METADATA_FIELD_SOURCE not in doc.metadata + assert vp.METADATA_FIELD_SOURCE not in doc.layers[1].metadata + assert doc.sources == tuple() + + +def test_read_by_attr_stdin_sets_source_properties(monkeypatch): + test_file = TEST_FILE_DIRECTORY / "misc" / "multilayer.svg" + monkeypatch.setattr("sys.stdin", io.StringIO(test_file.read_text())) + + doc = vpype_cli.execute(f"read -a stroke -a fill -") + assert vp.METADATA_FIELD_SOURCE not in doc.metadata + assert doc.sources == tuple() diff --git a/tests/test_property_substitution.py b/tests/test_property_substitution.py deleted file mode 100644 index 52bc2d54..00000000 --- a/tests/test_property_substitution.py +++ /dev/null @@ -1,58 +0,0 @@ -import pytest - -import vpype_cli - - -@pytest.mark.parametrize( - ("value", "field", "expected"), - [ - (3, "", "3"), - (3, "03", "003"), - (1.2, "", "1.2"), - (1.2, ".2f", "1.20"), - (1.2, "06.2f", "001.20"), - ("hello", "", "hello"), - ], -) -def test_property_substitution(runner, value, field, expected): - res = runner.invoke( - vpype_cli.cli, - f"propset -t {type(value).__name__} -g base_prop {value} " - f"propset -g result_prop {{base_prop:{field}}} " - "propget -g result_prop", - ) - assert res.exit_code == 0 - assert res.output.strip().split(" ")[-1] == expected - - -def test_property_substitution_layer(runner): - res = runner.invoke(vpype_cli.cli, "random -l1 propset -l 1 hello world text {hello}") - assert res.exit_code == 0 - - -def test_property_substitution_global(runner): - res = runner.invoke(vpype_cli.cli, "propset -g hello world text {hello}") - assert res.exit_code == 0 - - -def test_property_substitution_missing(runner): - res = runner.invoke(vpype_cli.cli, "propset -g hello world text {missing}") - assert res.exit_code == 2 - assert "Error" in res.stderr - - -def test_property_substitution_invalid(runner): - res = runner.invoke(vpype_cli.cli, "propset -g hello world text {hello:.2f}") - assert res.exit_code == 2 - assert "Error" in res.stderr - - -def test_property_substitution_int(): - doc = vpype_cli.execute("propset -g -t int num 2 repeat 2 random -l new end") - assert {1, 2} == doc.layers.keys() - - -def test_property_substitution_empty_layer(): - # property substitution should work even if the layer is empty - doc = vpype_cli.execute("pens rgb text {vp_name}") - assert len(doc.layers[1]) > 0 diff --git a/tests/test_reference_output.py b/tests/test_reference_output.py new file mode 100644 index 00000000..71e25c52 --- /dev/null +++ b/tests/test_reference_output.py @@ -0,0 +1,26 @@ +import pytest + +import vpype_cli + + +@pytest.mark.parametrize( + "cmd", + [ + "line 0 0 10 10 write '{path}'", + """pens cmyk grid -o 10cm 10cm 2 2 rect -l new 1cm 1cm 8cm 8cm end + layout a4 write '{path}'""", + ], +) +def test_reference_output(reference_svg, runner, cmd): + with reference_svg() as path: + res = runner.invoke(vpype_cli.cli, cmd.format(path=path)) + assert res.exit_code == 0 + + +@pytest.mark.xfail +def test_reference_output_fail(reference_svg, runner): + # ensure that SVG comparison indeed fails when it should + with reference_svg() as path: + res = runner.invoke(vpype_cli.cli, f"line 0 0 10 0 write '{path}'") + assert res.exit_code == 0 + path.write_text(path.read_text().replace("", "")) diff --git a/tests/test_substitution.py b/tests/test_substitution.py new file mode 100644 index 00000000..ccbd60b1 --- /dev/null +++ b/tests/test_substitution.py @@ -0,0 +1,242 @@ +import click +import pytest + +import vpype as vp +import vpype_cli + +# noinspection PyProtectedMember +from vpype_cli.substitution import ( + ExpressionSubstitutionError, + PropertySubstitutionError, + _PropertyProxy, + _substitute_expressions, +) + + +@pytest.mark.parametrize( + ("value", "field", "expected"), + [ + (3, "", "3"), + (3, "03", "003"), + (1.2, "", "1.2"), + (1.2, ".2f", "1.20"), + (1.2, "06.2f", "001.20"), + ("hello", "", "hello"), + ], +) +def test_property_substitution(runner, value, field, expected): + res = runner.invoke( + vpype_cli.cli, + f"propset -t {type(value).__name__} -g base_prop {value} " + f"propset -g result_prop {{base_prop:{field}}} " + "propget -g result_prop", + ) + assert res.exit_code == 0 + assert res.output.strip().split(" ")[-1] == expected + + +def test_property_substitution_layer(runner): + res = runner.invoke(vpype_cli.cli, "random -l1 propset -l 1 hello world text {hello}") + assert res.exit_code == 0 + + +def test_property_substitution_global(runner): + res = runner.invoke(vpype_cli.cli, "propset -g hello world text {hello}") + assert res.exit_code == 0 + + +def test_property_substitution_missing(runner): + res = runner.invoke(vpype_cli.cli, "propset -g hello world text {missing}") + assert res.exit_code == 2 + assert "Error" in res.stderr + + +def test_property_substitution_invalid(runner): + res = runner.invoke(vpype_cli.cli, "propset -g hello world text {hello:.2f}") + assert res.exit_code == 2 + assert "Error" in res.stderr + + +def test_property_substitution_int(): + doc = vpype_cli.execute("propset -g -t int num 2 repeat 2 random -l new end") + assert {1, 2} == doc.layers.keys() + + +def test_property_substitution_empty_layer(): + # property substitution should work even if the layer is empty + doc = vpype_cli.execute("pens rgb text {vp_name}") + assert len(doc.layers[1]) > 0 + + +@pytest.fixture +def state_factory(): + def make_state(state_type: str = "default") -> vpype_cli.State: + if state_type == "default": + state = vpype_cli.State() + elif state_type == "inconsistent": + state = vpype_cli.State() + state.current_layer_id = 1 # doesn't exists + elif state_type == "dummy": + doc = vp.Document() + doc.set_property("global_prop", 10) + doc.add([[0, 10, 10j]], 1) + doc.layers[1].set_property("layer_prop", 1.5) + state = vpype_cli.State(doc) + state.current_layer_id = 1 + else: # pragma: no cover + raise ValueError(f"unknown state type {state_type}") + return state + + return make_state + + +def test_property_proxy(state_factory): + dummy_state = state_factory("dummy") + proxy = _PropertyProxy(dummy_state, True, True) + assert proxy["global_prop"] == proxy.global_prop == 10 + assert proxy["layer_prop"] == proxy.layer_prop == 1.5 + + proxy = _PropertyProxy(dummy_state, True, False) + assert proxy["global_prop"] == proxy.global_prop == 10 + with pytest.raises(KeyError): + assert proxy["local_prop"] + with pytest.raises(AttributeError): + assert proxy.local_prop + + proxy = _PropertyProxy(dummy_state, False, True) + assert proxy["layer_prop"] == proxy.layer_prop == 1.5 + with pytest.raises(KeyError): + assert proxy["global_prop"] + with pytest.raises(AttributeError): + assert proxy.global_prop + + +def test_property_proxy_dict(state_factory): + dummy_state = state_factory("dummy") + + assert dict(_PropertyProxy(dummy_state, True, True)) == { + "global_prop": 10, + "layer_prop": 1.5, + } + assert dict(_PropertyProxy(dummy_state, True, False)) == {"global_prop": 10} + assert dict(_PropertyProxy(dummy_state, False, True)) == {"layer_prop": 1.5} + + +@pytest.fixture +def dumb_interp(): + def interp(text: str) -> str: + return f"###{text}###" + + return interp + + +@pytest.fixture +def dumb_prop(): + class _DumbProp(dict): + def __missing__(self, key): + return f"$$${key}$$$" + + return lambda x: x.format_map(_DumbProp()) + + +@pytest.mark.parametrize( + ("text", "expected"), + ( + # basic properties + ("{hello}", "$$$hello$$$"), + ("world{hello}", "world$$$hello$$$"), + ("{hello}world", "$$$hello$$$world"), + ("{hello}world{bis}", "$$$hello$$$world$$$bis$$$"), + ("first{hello}world{bis}last", "first$$$hello$$$world$$$bis$$$last"), + ("{{hello}}", "{hello}"), + ("{{hello}}{world}", "{hello}$$$world$$$"), + ("he%%llo{world}", "he%llo$$$world$$$"), + ("he%%ll{{}}o{world}", "he%ll{}o$$$world$$$"), + # basic expression + ("%%", "%"), + ("hello", "hello"), + ("%hello%", "###hello###"), + ("%hel%%lo%", "###hel%lo###"), + ("hel%%lo", "hel%lo"), + ("hel%%lo%world%", "hel%lo###world###"), + ("hel%%lo%wor%%ld%", "hel%lo###wor%ld###"), + ("hel%%lo%wor%%ld%bye", "hel%lo###wor%ld###bye"), + ("hel%%lo%wor%%ld%by%%e", "hel%lo###wor%ld###by%e"), + # combined + ("%hello%{world}", "###hello###$$$world$$$"), + ("%he{ll}o%", "###he{ll}o###"), + ("{{hello:.1%}}%", "{hello:.1###}}###"), + ), +) +def test_substitute_expressions(dumb_prop, dumb_interp, text, expected): + assert _substitute_expressions(text, dumb_prop, dumb_interp) == expected + + +def test_substitution_percent_property_format(state_factory): + """Special case where % should be accepted in prop substitution""" + dummy_state = state_factory("dummy") + assert dummy_state.substitute("{layer_prop:.2%}") == "150.00%" + assert dummy_state.substitute("{layer_prop:.2%} %lprop.layer_prop%") == "150.00% 1.5" + + +@pytest.mark.parametrize( + "text", + ( + "%", + "%%%", + "%hello", + "%hel%%lo", + "%hello%world%", + "%hello%world%bye", + "hello%world%bye%", + ), +) +def test_expression_illegal(text, dumb_interp): + with pytest.raises(ExpressionSubstitutionError): + _substitute_expressions(text, lambda x: x, dumb_interp) + + +@pytest.mark.parametrize( + "text", + ( + "{he{{ll}}o}", # invalid for format + "{hello}}world", + ), +) +def test_property_illegal(text, dumb_prop): + with pytest.raises(PropertySubstitutionError): + _substitute_expressions(text, dumb_prop, lambda x: x) + + +def test_expression_get_property(state_factory): + dummy_state = state_factory("dummy") + + assert dummy_state.substitute("%prop.global_prop%") == "10" + assert dummy_state.substitute("%prop.layer_prop%") == "1.5" + assert dummy_state.substitute("%gprop.global_prop%") == "10" + assert dummy_state.substitute("%lprop.layer_prop%") == "1.5" + with pytest.raises(click.BadParameter): + dummy_state.substitute("%lprop.global_prop%") + with pytest.raises(click.BadParameter): + dummy_state.substitute("%gprop.layer_prop%") + + +def test_expression_set_property(state_factory): + dummy_state = state_factory("dummy") + + dummy_state.substitute("%gprop.new_global_prop='alpha'%") + assert dummy_state.document.property("new_global_prop") == "alpha" + + dummy_state.substitute("%lprop.new_layer_prop=50%") + assert dummy_state.document.layers[1].property("new_layer_prop") == 50 + + with pytest.raises(click.BadParameter): + dummy_state.substitute("%prop.new_prop=1%") + + +@pytest.mark.parametrize("state_type", ("dummy", "default", "inconsistent")) +def test_expression_dict_of_prop(state_factory, state_type): + state = state_factory(state_type) + state.substitute("%dict(prop)%") + state.substitute("%dict(gprop)%") + state.substitute("%dict(lprop)%") diff --git a/vpype/io.py b/vpype/io.py index 24c53e26..6e064601 100644 --- a/vpype/io.py +++ b/vpype/io.py @@ -5,6 +5,7 @@ import dataclasses import datetime import math +import pathlib import re from typing import Any, Dict, Iterable, Iterator, List, Optional, TextIO, Tuple, Union, cast from xml.etree import ElementTree @@ -24,6 +25,7 @@ METADATA_FIELD_COLOR, METADATA_FIELD_NAME, METADATA_FIELD_PEN_WIDTH, + METADATA_FIELD_SOURCE, METADATA_SVG_ATTRIBUTES_WHITELIST, METADATA_SVG_NAMESPACES, Color, @@ -362,6 +364,17 @@ def _process_path(path): return lc +def _get_source(file: Union[str, TextIO]) -> Optional[pathlib.Path]: + try: + path = pathlib.Path(file) # type: ignore + if path.exists(): + return path + except TypeError: + pass + + return None + + def read_svg( file: Union[str, TextIO], quantization: float, @@ -401,6 +414,10 @@ def read_svg( if crop: lc.crop(0, 0, svg.width, svg.height) + source = _get_source(file) + if source: + lc.set_property(METADATA_FIELD_SOURCE, source) + return lc, svg.width, svg.height @@ -501,6 +518,11 @@ def _find_groups(group: svgelements.Group) -> Iterator[svgelements.Group]: for layer in document.layers.values(): layer.metadata = dict(layer.metadata.items() - document.metadata.items()) + source = _get_source(file) + if source: + document.set_property(METADATA_FIELD_SOURCE, source) + document.add_to_sources(source) + return document @@ -560,6 +582,11 @@ def read_svg_by_attributes( for layer in document.layers.values(): layer.metadata = dict(layer.metadata.items() - document.metadata.items()) + source = _get_source(file) + if source: + document.set_property(METADATA_FIELD_SOURCE, source) + document.add_to_sources(source) + return document diff --git a/vpype/metadata.py b/vpype/metadata.py index 82169d2b..32f7f1c6 100644 --- a/vpype/metadata.py +++ b/vpype/metadata.py @@ -1,4 +1,5 @@ import dataclasses +import pathlib from typing import Optional, Tuple, Union import svgelements @@ -66,6 +67,8 @@ def __str__(self) -> str: METADATA_FIELD_NAME = "vp_name" METADATA_FIELD_COLOR = "vp_color" METADATA_FIELD_PEN_WIDTH = "vp_pen_width" +METADATA_FIELD_SOURCE = "vp_source" +METADATA_FIELD_SOURCE_LIST = "vp_sources" # global metadata field names METADATA_FIELD_SVG_NAMESPACES = "vp_svg_ns" @@ -76,6 +79,8 @@ def __str__(self) -> str: METADATA_FIELD_COLOR: Color, METADATA_FIELD_PEN_WIDTH: float, METADATA_FIELD_PAGE_SIZE: tuple, + METADATA_FIELD_SOURCE: pathlib.Path, + METADATA_FIELD_SOURCE_LIST: tuple, } # noinspection HttpUrlsUsage diff --git a/vpype/model.py b/vpype/model.py index a5a7201b..e18bb14a 100644 --- a/vpype/model.py +++ b/vpype/model.py @@ -1,6 +1,7 @@ """Implementation of vpype's data model """ import math +import pathlib from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast import numpy as np @@ -8,7 +9,11 @@ from .geometry import crop, reloop from .line_index import LineIndex -from .metadata import METADATA_FIELD_PAGE_SIZE, METADATA_SYSTEM_FIELD_TYPES +from .metadata import ( + METADATA_FIELD_PAGE_SIZE, + METADATA_FIELD_SOURCE_LIST, + METADATA_SYSTEM_FIELD_TYPES, +) __all__ = [ "LineCollection", @@ -139,17 +144,17 @@ class LineCollection(_MetadataMixin): Finally, :py:class:`LineCollection` implements a number of operations such as geometrical transformation, cropping, merging, etc. (see member function documentation for details). + + Args: + lines (LineCollectionLike): iterable of line (accepts the same input as + :func:`~LineCollection.append`). + metadata: if provided, used as layer metadata """ def __init__( self, lines: LineCollectionLike = (), metadata: Optional[Dict[str, Any]] = None ): - """Create a LineCollection instance from an iterable of lines. - - Args: - lines (LineCollectionLike): iterable of line (accepts the same input as - :func:`~LineCollection.append`). - """ + """Create a LineCollection instance from an iterable of lines.""" super().__init__(metadata) self._lines: List[np.ndarray] = [] @@ -505,6 +510,11 @@ class Document(_MetadataMixin): In addition, the Document class maintains a :py:attr:`page_size` attribute which describe the physical size of the document. This attribute is not strictly linked to the actual Document's content, but can be set based on it. + + Args: + line_collection: if provided, used as layer 1 + metadata: if provided, used as global metadata + page_size: if provided, used as page size """ def __init__( @@ -589,6 +599,30 @@ def extend_page_size(self, page_size: Optional[Tuple[float, float]]) -> None: else: self.page_size = page_size + @property + def sources(self) -> Tuple[pathlib.Path, ...]: + return self.metadata.get(METADATA_FIELD_SOURCE_LIST, tuple()) + + @sources.setter + def sources(self, sources: Tuple[pathlib.Path, ...]) -> None: + self.set_property(METADATA_FIELD_SOURCE_LIST, sources) + + def add_to_sources(self, path) -> None: + """Add a path to the source list. + + If ``path`` cannot be converted to a :class:`pathlib.Path` or the file doesn't exist, + it is ignored and not added to the source list. + + Args: + path: file path + """ + try: + path = pathlib.Path(path) + if path.exists(): + self.sources += (path,) + except TypeError: + pass + def clear_layer_metadata(self) -> None: """Clear all metadata from the document.""" for layer in self._layers.values(): @@ -653,11 +687,24 @@ def free_id(self) -> int: vid += 1 return vid - def add(self, lines: LineCollectionLike, layer_id: Union[None, int] = None) -> None: + def add( + self, + lines: LineCollectionLike, + layer_id: Union[None, int] = None, + with_metadata: bool = False, + ) -> None: """Add a the content of a :py:class:`LineCollection` to a given layer. - If the given layer is None, a new layer with the lowest available layer ID is created - (with emtpy metadata) and initialized with the content of ``lc``. + If the given layer ID is :data:`None`, a new layer with the lowest available layer ID + is created and initialized with the content of ``lc``. + + The destination layer's metadata is unchanged, unless ``with_metadata`` is + :data:`True`. + + Args: + lines: lines to add to the layer + layer_id: the destination layer ID, or :data:`None` for a new layer + with_metadata: copies/update the metadata to the destination layer (if any) """ if layer_id is None: layer_id = 1 @@ -669,17 +716,24 @@ def add(self, lines: LineCollectionLike, layer_id: Union[None, int] = None) -> N self._layers[layer_id].extend(lines) - def replace(self, lines: LineCollectionLike, layer_id: int) -> None: + if with_metadata and isinstance(lines, LineCollection): + self._layers[layer_id].metadata.update(lines.metadata) + + def replace( + self, lines: LineCollectionLike, layer_id: int, *, with_metadata: bool = False + ) -> None: """Replaces the content of a layer. This method replaces the content of layer ``layer_id`` with ``lines``. The layer must exist, otherwise a :class:`ValueError` exception is raised. - The destination layer retains its metadata + The destination layer retains its metadata, unless ``with_metadata`` is True, in which + case ``lines`` must have a ``metadata`` attribute. Args: lines: line data to assign to the layer layer_id: layer ID of the layer whose content is to be replaced + with_metadata: """ if layer_id not in self._layers: @@ -687,6 +741,11 @@ def replace(self, lines: LineCollectionLike, layer_id: int) -> None: self._layers[layer_id] = self._layers[layer_id].clone(lines) + if with_metadata: + metadata = getattr(lines, "metadata", None) + if metadata is not None: + self._layers[layer_id].metadata = metadata.copy() + def swap_content(self, lid1: int, lid2: int) -> None: """Swap the content of two layers. @@ -728,10 +787,16 @@ def extend(self, doc: "Document") -> None: doc: source Document """ - # special treatment for page size + # special treatment for page size and source list self.extend_page_size(doc.page_size) + for path in doc.sources: + self.add_to_sources(path) self.metadata.update( - {k: v for k, v in doc.metadata.items() if k != METADATA_FIELD_PAGE_SIZE} + { + k: v + for k, v in doc.metadata.items() + if k not in {METADATA_FIELD_PAGE_SIZE, METADATA_FIELD_SOURCE_LIST} + } ) for layer_id, layer in doc.layers.items(): diff --git a/vpype_cli/__init__.py b/vpype_cli/__init__.py index 51ad1410..4ffd3f29 100644 --- a/vpype_cli/__init__.py +++ b/vpype_cli/__init__.py @@ -6,6 +6,7 @@ from .cli import * from .debug import * from .decorators import * +from .eval import * from .filters import * from .frames import * from .generators import * diff --git a/vpype_cli/blocks.py b/vpype_cli/blocks.py index 690d5a0b..cdca627d 100644 --- a/vpype_cli/blocks.py +++ b/vpype_cli/blocks.py @@ -1,17 +1,22 @@ -from typing import Iterable, Tuple +import glob +import os +import pathlib +from typing import Any, Dict, Iterable, Tuple import click +import vpype as vp + from .cli import ProcessorType, cli, execute_processors from .decorators import block_processor from .state import State -from .types import IntegerType, LengthType +from .types import IntegerType, LengthType, TextType -__all__ = ("grid", "repeat") +__all__ = ("grid", "repeat", "forfile", "forlayer") @cli.command(group="Block processors") -@click.argument("number", nargs=2, default=(2, 2), type=IntegerType(), metavar="M N") +@click.argument("number", nargs=2, default=(2, 2), type=IntegerType(), metavar="NX NY") @click.option( "-o", "--offset", @@ -27,8 +32,8 @@ def grid( processors: Iterable[ProcessorType], number: Tuple[int, int], offset: Tuple[float, float], -) -> State: - """Creates a MxN grid of geometry +) -> None: + """Creates a NX by NY grid of geometry The number of column and row must always be specified. By default, 10mm offsets are used in both directions. Use the `--offset` option to override these values. @@ -38,6 +43,16 @@ def grid( nested commands are applied on the pipeline. However, the properties deleted by the nested commands are not deleted from the outer pipeline. + The following variables are set by `grid` and available for expressions: + + \b + _nx: number of columns (NX) + _ny: number of rows (NY) + _n: total number of cell (NX*NY) + _x: current column (0 to NX-1) + _y: current row (0 to NY-1) + _i: current cell (0 to _n-1) + Examples: Create a grid of random line patches: @@ -49,19 +64,30 @@ def grid( $ vpype begin grid -o 3cm 3cm 2 3 circle --layer new 0 0 1cm end show """ - for j in range(number[1]): - for i in range(number[0]): - with state.clear_document(): + nx, ny = number + + for j in range(ny): + for i in range(nx): + variables = { + "_nx": nx, + "_ny": ny, + "_n": nx * ny, + "_x": i, + "_y": j, + "_i": i + j * nx, + } + with state.temp_document() as doc, state.expression_variables(variables): execute_processors(processors, state) - state.document.translate(offset[0] * i, offset[1] * j) + doc.translate(offset[0] * i, offset[1] * j) + state.document.extend(doc) + if nx > 0 and ny > 0: + state.document.page_size = (nx * offset[0], ny * offset[1]) - return state - -@cli.command("repeat", group="Block processors") +@cli.command(group="Block processors") @click.argument("number", type=IntegerType(), metavar="N") @block_processor -def repeat(state: State, processors: Iterable[ProcessorType], number: int) -> State: +def repeat(state: State, processors: Iterable[ProcessorType], number: int) -> None: """Repeat geometries N times. Repeats the enclosed command N times, stacking their output on top of each other. @@ -71,15 +97,145 @@ def repeat(state: State, processors: Iterable[ProcessorType], number: int) -> St nested commands are applied on the pipeline. However, the properties deleted by the nested commands are not deleted from the outer pipeline. + The following variables are set by `repeat` and available for expressions: + + \b + _n: number of repetition + _i: counter (0 to _n-1) + Examples: Create a patch of random lines of 3 different colors: - $ vpype begin repeat 3 random --layer new end show + $ vpype begin repeat 3 random --layer %_i+1% end show + """ + + for i in range(number): + variables = {"_n": number, "_i": i} + with state.temp_document() as doc, state.expression_variables(variables): + execute_processors(processors, state) + state.document.extend(doc) + + +@cli.command(group="Block processors") +@click.argument("files", type=TextType(), metavar="FILES") +@block_processor +def forfile(state: State, processors: Iterable[ProcessorType], files: str) -> None: + """Iterate over a file list. + + The `forfile` block processor expends the FILES pattern into a file list like a shell + would. In particular, wildcards (`*` and `**`) are expended, environmental variables are + substituted (`$ENVVAR`), and the `~` expended to the user directory. It then executes the + nested commands once for each file. + + The following variables are set by `forfile` and available for expressions: + + \b + _path (pathlib.Path): file path + _name (str): file name (e.g. 'input.svg') + _parent (pathlib.Path): parent directory + _ext (str): file extension (e.g. '.svg') + _stem (str): file name without extension (e.g. 'input') + _n (int): total number of files + _i (int): counter (0 to _n-1) + + Example: + + Process all SVGs in the current directory: + + \b + $ vpype begin forfile \*.svg read %_path% linemerge linesort \\ + write "optimized/%basename(_path)%" end """ - for _ in range(number): - with state.clear_document(): + file_list = glob.glob(os.path.expandvars(os.path.expanduser(files))) + + for i, file in enumerate(file_list): + path = pathlib.Path(file) + variables = { + "_path": path, + "_name": path.name, + "_parent": path.parent, + "_ext": path.suffix, + "_stem": path.stem, + "_i": i, + "_n": len(files), + } + with state.temp_document() as doc, state.expression_variables(variables): execute_processors(processors, state) + state.document.extend(doc) + + +class _MetadataProxy: + def __init__(self, metadata: Dict[str, Any]): + self._metadata = metadata + + def __getattr__(self, name): + if name in self._metadata: + return self._metadata[name] + else: + raise AttributeError(f"property '{name}' not found") + + def __setattr__(self, name, value): + if name == "_metadata": + super().__setattr__(name, value) + else: + self._metadata[name] = value + + def __getitem__(self, name): + return self._metadata[name] + + def __setitem__(self, name, value): + self._metadata[name] = value + + +@cli.command(group="Block processors") +@block_processor +def forlayer(state: State, processors: Iterable[ProcessorType]) -> None: + """Iterate over each layer. + + This block processor execute the nested pipeline once per layer. The nested pipeline is + exclusively exposed to the current layer. In addition, if the nested commands create any + other layer, they are merged as well into the outer pipeline. + + The following variables are set by `forlayer` and available for expressions: + + \b + _lid (int): the current layer ID + _name (str): the name of the current layer + _color (Color): the color of the current layer + _pen_width (float): the pen width of the current layer + _prop: properties of the current layer (accessible by item and/or attribute) + _i (int): counter (0 to _n-1) + _n (int): number of layers + + Example: + + Export one file per layer: + + vpype read input.svg forlayer write output_%_name%.svg end + """ + + orig_doc = state.document + new_doc: vp.Document = orig_doc.clone() + + for i, lid in enumerate(list(orig_doc.layers)): + with state.temp_document(keep_layer=False) as doc: + doc.add(orig_doc.pop(lid), lid, with_metadata=True) + variables = { + "_lid": lid, + "_i": i, + "_n": len(doc.layers), + "_name": doc.layers[lid].property(vp.METADATA_FIELD_NAME) or "", + "_color": doc.layers[lid].property(vp.METADATA_FIELD_COLOR), + "_pen_width": doc.layers[lid].property(vp.METADATA_FIELD_PEN_WIDTH), + "_prop": _MetadataProxy(doc.layers[lid].metadata), + } + with state.expression_variables(variables): + execute_processors(processors, state) + new_doc.extend(doc) - return state + # The original document's content has been entirely popped and can be restored. + # Note: we *cannot* replace state.document by new_doc, as this interferes with + # state.temp_document() and ultimately breaks nested blocks + state.document.extend(new_doc) diff --git a/vpype_cli/cli.py b/vpype_cli/cli.py index 8cd1b920..ce228770 100644 --- a/vpype_cli/cli.py +++ b/vpype_cli/cli.py @@ -4,7 +4,7 @@ import shlex import sys import traceback -from typing import Any, Callable, Iterable, List, Optional, TextIO, Union, cast +from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Optional, TextIO, Union, cast import click import numpy as np @@ -211,6 +211,11 @@ def cli(ctx, verbose, include, history, seed, config): vp.config_manager.load_config_file(config) +# this is somehow needed to make PyCharm happy with runner.invoke(cli, ...) +if TYPE_CHECKING: # pragma: no cover + cli = cast(GroupedGroup, cli) + + # noinspection PyShadowingNames,PyUnusedLocal @cli.result_callback() def process_pipeline(processors, verbose, include, history, seed, config): @@ -298,7 +303,7 @@ def block_processor_placeholder( # the (only) frame's processors should now be flat and can be chain-called for proc in outer_processors: - state = cast(Callable, proc)(state) + cast(Callable, proc)(state) class BeginBlock: diff --git a/vpype_cli/decorators.py b/vpype_cli/decorators.py index aa45be3c..935adbfe 100644 --- a/vpype_cli/decorators.py +++ b/vpype_cli/decorators.py @@ -77,17 +77,18 @@ def new_func(*args, **kwargs): layers = kwargs.pop("layer", []) # noinspection PyShadowingNames - def layer_processor(state: State) -> State: - for lid in multiple_to_layer_ids(layers, state.document): - logging.info( - f"executing layer processor `{f.__name__}` on layer {lid} " - f"(kwargs: {kwargs})" - ) + def layer_processor(state: State) -> None: + layers_eval = state.preprocess_argument(layers) + for lid in multiple_to_layer_ids(layers_eval, state.document): start = datetime.datetime.now() with state.current(): state.current_layer_id = lid - new_args, new_kwargs = state.evaluate_parameters(args, kwargs) + new_args, new_kwargs = state.preprocess_arguments(args, kwargs) + logging.info( + f"executing layer processor `{f.__name__}` on layer {lid} " + f"(kwargs: {new_kwargs})" + ) state.document[lid] = f(state.document[lid], *new_args, **new_kwargs) state.current_layer_id = None stop = datetime.datetime.now() @@ -97,8 +98,6 @@ def layer_processor(state: State) -> State: f"({_format_timedelta(stop - start)})" ) - return state - return layer_processor return update_wrapper(new_func, f) @@ -147,12 +146,13 @@ def my_global_processor( def new_func(*args, **kwargs): # noinspection PyShadowingNames - def global_processor(state: State) -> State: - logging.info(f"executing global processor `{f.__name__}` (kwargs: {kwargs})") - + def global_processor(state: State) -> None: start = datetime.datetime.now() with state.current(): - new_args, new_kwargs = state.evaluate_parameters(args, kwargs) + new_args, new_kwargs = state.preprocess_arguments(args, kwargs) + logging.info( + f"executing global processor `{f.__name__}` (kwargs: {new_kwargs})" + ) state.document = f(state.document, *new_args, **new_kwargs) stop = datetime.datetime.now() @@ -161,8 +161,6 @@ def global_processor(state: State) -> State: f"({_format_timedelta(stop - start)})" ) - return state - return global_processor return update_wrapper(new_func, f) @@ -187,18 +185,18 @@ def new_func(*args, **kwargs): layer = kwargs.pop("layer", None) # noinspection PyShadowingNames - def generator(state: State) -> State: + def generator(state: State) -> None: with state.current(): - target_layer = single_to_layer_id(layer, state.document) + layer_eval = state.preprocess_argument(layer) + target_layer = single_to_layer_id(layer_eval, state.document) + start = datetime.datetime.now() + state.current_layer_id = target_layer + new_args, new_kwargs = state.preprocess_arguments(args, kwargs) logging.info( f"executing generator `{f.__name__}` to layer {target_layer} " - f"(kwargs: {kwargs})" + f"(kwargs: {new_kwargs})" ) - - start = datetime.datetime.now() - state.current_layer_id = target_layer - new_args, new_kwargs = state.evaluate_parameters(args, kwargs) state.document.add(f(*new_args, **new_kwargs), target_layer) state.current_layer_id = None stop = datetime.datetime.now() @@ -210,8 +208,6 @@ def generator(state: State) -> State: f"({_format_timedelta(stop - start)})" ) - return state - return generator return update_wrapper(new_func, f) @@ -243,11 +239,12 @@ def my_block_processor(state: vpype_cli.State, processors) -> vpype_cli.State: def new_func(*args, **kwargs): # noinspection PyShadowingNames - def block_processor(state: State, processors: Iterable["ProcessorType"]) -> State: + def block_processor(state: State, processors: Iterable["ProcessorType"]) -> None: logging.info(f"executing block processor `{f.__name__}` (kwargs: {kwargs})") start = datetime.datetime.now() - new_args, new_kwargs = state.evaluate_parameters(args, kwargs) + new_args, new_kwargs = state.preprocess_arguments(args, kwargs) + logging.info(f"executing block processor `{f.__name__}` (kwargs: {new_kwargs})") f(state, processors, *new_args, **new_kwargs) stop = datetime.datetime.now() @@ -256,8 +253,6 @@ def block_processor(state: State, processors: Iterable["ProcessorType"]) -> Stat f"({_format_timedelta(stop - start)})" ) - return state - # mark processor as being a block processor, needed by execute_processors() block_processor.__vpype_block_processor__ = True return block_processor diff --git a/vpype_cli/eval.py b/vpype_cli/eval.py new file mode 100644 index 00000000..53161485 --- /dev/null +++ b/vpype_cli/eval.py @@ -0,0 +1,42 @@ +import logging + +import click + +import vpype as vp + +from .cli import cli +from .decorators import global_processor, pass_state +from .state import State + + +@cli.command("eval", group="Expressions") +@click.argument("expr", type=str) +@global_processor +@pass_state +def eval_cmd(state: State, document: vp.Document, expr: str): + """Evaluate an expression. + + This command is a placeholder whose only purpose is to evaluate EXPR. It has no effect on + the geometries, nor their properties. It is typically used at the beginning of a pipeline + to initialise expression variables used later on. + + EXPR is interpreted as an expression in its entirety. As such, the enclosing `%` expression + markers may be omitted. + + Example: + + Crop the geometry to a 1-cm margin. + + \b + $ vpype read input.svg eval "m = 1*cm; w,h = prop.vp_page_size" \\ + crop %m% %m% %w-2*m% %h-2*m% write output.svg + """ + + if not expr.startswith("%"): + expr = "%" + expr + if not expr.endswith("%"): + expr += "%" + res = state.substitute(expr) + logging.debug(f"eval: expression evaluated to {res}") + + return document diff --git a/vpype_cli/operations.py b/vpype_cli/operations.py index 8d474b90..8ccfe364 100644 --- a/vpype_cli/operations.py +++ b/vpype_cli/operations.py @@ -165,7 +165,7 @@ def linesort(lines: vp.LineCollection, no_flip: bool, two_opt: bool, passes: int return lines line_index = vp.LineIndex(lines[1:], reverse=not no_flip) - new_lines = vp.LineCollection([lines[0]]) + new_lines = lines.clone([lines[0]]) while len(line_index) > 0: # noinspection PyShadowingNames diff --git a/vpype_cli/read.py b/vpype_cli/read.py index ad5731b7..ddec4bd1 100644 --- a/vpype_cli/read.py +++ b/vpype_cli/read.py @@ -1,4 +1,5 @@ import logging +import pathlib import sys from typing import List, Optional, Tuple @@ -8,13 +9,13 @@ from .cli import cli from .decorators import global_processor -from .types import LayerType, LengthType, PageSizeType, single_to_layer_id +from .types import LayerType, LengthType, PageSizeType, PathType, single_to_layer_id __all__ = ("read",) @cli.command(group="Input") -@click.argument("file", type=click.Path(exists=True, dir_okay=False, allow_dash=True)) +@click.argument("file", type=PathType(dir_okay=False, allow_dash=True)) @click.option("-m", "--single-layer", is_flag=True, help="Single layer mode.") @click.option( "-l", @@ -36,6 +37,7 @@ default="0.1mm", help="Maximum length of segments approximating curved elements (default: 0.1mm).", ) +@click.option("--no-fail", is_flag=True, help="Do not fail is the target file doesn't exist.") @click.option( "-s", "--simplify", @@ -82,6 +84,7 @@ def read( layer: Optional[int], attr: List[str], quantization: float, + no_fail: bool, simplify: bool, parallel: bool, no_crop: bool, @@ -188,10 +191,16 @@ def read( if file == "-": file = sys.stdin + elif not pathlib.Path(file).is_file(): + if no_fail: + logging.debug("read: file doesn't exist, ignoring due to `--no-fail`") + return document + else: + raise click.BadParameter(f"file {file!r} does not exist") if layer is not None and not single_layer: single_layer = True - logging.info("read: `--layer` provided, assuming single-layer mode") + logging.debug("read: `--layer` provided, assuming single-layer mode") if single_layer: if len(attr) > 0: @@ -207,8 +216,9 @@ def read( default_height=height, ) - document.add(lc, single_to_layer_id(layer, document)) + document.add(lc, single_to_layer_id(layer, document), with_metadata=True) document.extend_page_size((width, height)) + document.add_to_sources(file) else: if len(attr) == 0: doc = vp.read_multilayer_svg( diff --git a/vpype_cli/state.py b/vpype_cli/state.py index 7c088444..9b311aa6 100644 --- a/vpype_cli/state.py +++ b/vpype_cli/state.py @@ -1,31 +1,18 @@ from abc import ABC, abstractmethod from contextlib import contextmanager -from typing import Any, Dict, Optional, Tuple, Union +from typing import Any, Dict, Generator, Optional, Tuple, Union import click import vpype as vp -__all__ = ("State", "_DeferredEvaluator") - - -class _SubstitutionHelper: - """Dict-like class for :ref:`property substitution ` - using :meth:`str.format_map`.""" - - def __init__( - self, document: Optional[vp.Document] = None, layer: Optional[vp.LineCollection] = None - ): - self.document = document - self.layer = layer +from .substitution import ( + ExpressionSubstitutionError, + PropertySubstitutionError, + SubstitutionHelper, +) - def __getitem__(self, item): - if self.layer is not None and self.layer.property_exists(item): - return self.layer.property(item) - elif self.document is not None and self.document.property_exists(item): - return self.document.property(item) - else: - raise click.BadParameter(f"Cannot substitute {{{item}}}: property not found") +__all__ = ("State", "_DeferredEvaluator") class _DeferredEvaluator(ABC): @@ -42,14 +29,21 @@ class _DeferredEvaluator(ABC): instances, perform the conversion, and forward the converted value to the command function. """ - def __init__(self, text: str): + def __init__(self, text: str, param_name: str, *args, **kwargs): self._text = text + self._param_name = param_name @abstractmethod def evaluate(self, state: "State") -> Any: """Sub-class must override this function and return the converted value of ``self._text``""" + def __str__(self): + return self._text + + def __repr__(self): + return repr(self._text) + class State: """Encapsulates the current state of the *vpype* pipeline processing. @@ -57,6 +51,9 @@ class State: This class encapsulates the current state of the pipeline and provides services to commands. To access the current state instance, a command must use the :func:`pass_state` decorator. + + Args: + document: if provided, use this document """ _current_state: Union["State", None] = None @@ -73,48 +70,62 @@ def __init__(self, document: Optional[vp.Document] = None): #: :func:`layer_processor` command. self.current_layer_id: Optional[int] = None - def _evaluate_arg(self, arg: Any) -> Any: + self._interpreter = SubstitutionHelper(self) + + def preprocess_argument(self, arg: Any) -> Any: + """Evaluate an argument. + + If ``arg`` is a :class:`_DeferredEvaluator` instance, evaluate it a return its value + instead. + + Args: + arg: argument to evaluate + + Returns: + returns the fully evaluated ``arg`` + """ if isinstance(arg, tuple): - return tuple(self._evaluate_arg(item) for item in arg) + return tuple(self.preprocess_argument(item) for item in arg) else: return arg.evaluate(self) if isinstance(arg, _DeferredEvaluator) else arg - def evaluate_parameters( + def preprocess_arguments( self, args: Tuple[Any, ...], kwargs: Dict[str, Any] ) -> Tuple[Tuple[Any, ...], Dict[str, Any]]: - """Replace any instance of :class:`_DeferredEvaluator` and replace them with the + """Evaluate any instance of :class:`_DeferredEvaluator` and replace them with the converted value. """ return ( - tuple(self._evaluate_arg(arg) for arg in args), - {k: self._evaluate_arg(v) for k, v in kwargs.items()}, + tuple(self.preprocess_argument(arg) for arg in args), + {k: self.preprocess_argument(v) for k, v in kwargs.items()}, ) - def substitute_input(self, txt: str) -> str: - """Apply :ref:`property substitution ` on input - from user. - - Command implementation should favour using one (or more) of the types which have - built-in substitution, such as :class:`TextType`, :class:`LengthType`, etc. This method - may be used in cases where using types is not appropriate. + def substitute(self, text: str) -> str: + """Apply :ref:`property ` and + :ref:`expression ` substitution on user input. Args: - txt: input text on which to apply substitution + text: user input on which to perform the substitution Returns: - fully-substituted text + fully substituted text """ - helper = _SubstitutionHelper( - self.document, - self.document.layers[self.current_layer_id] - if self.current_layer_id in self.document.layers - else None, - ) - try: - return txt.format_map(helper) - except ValueError as exc: - raise click.BadParameter("Could not perform substitution: " + exc.args[0]) + return self._interpreter.substitute(text) + except (ExpressionSubstitutionError, PropertySubstitutionError) as exc: + cause_err = "Error" + cause = getattr(exc, "__cause__", None) + if cause: + cause_err = cause.__class__.__name__ + type_err = ( + "expression" if isinstance(exc, ExpressionSubstitutionError) else "property" + ) + details = "" + if cause and len(cause.args) > 0: + details = ": " + cause.args[0] + raise click.BadParameter( + f"{cause_err} with {type_err} substitution{details}" + ) from exc @classmethod def get_current(cls): @@ -132,17 +143,66 @@ def current(self): self.__class__._current_state = None @contextmanager - def clear_document(self): - """Context manager to temporarily clear and extend the state's document. + def temp_document(self, keep_layer: bool = True) -> Generator[vp.Document, None, None]: + """Context manager to temporarily clear the state's document. + + This context manager is typically used by block processor to temporarily clear the + document of line data while retaining its structure when executing nested processors. + The context manager returns the temporary document instance. It is typically used by + block processors to extend the original document after running the nested commands. - This context manager is typically used by block processor to clear the document of - line data while retaining its structure when executing nested processors, and then - add the generated geometries to the original document. See :func:`block` for an - example. + Args: + keep_layer: keep the layer structure + + Returns: + the temporary document instance + + Example:: + + >>> import vpype_cli + >>> @vpype_cli.cli.command() + ... @vpype_cli.block_processor + ... def clean_block(state, processors): + ... with state.temp_document() as temp_doc: + ... # state.document is now empty but has the same structure as the + ... # original document + ... vpype_cli.execute_processors(processors, state) + ... # update the original document with the temporary one + ... state.document.extend(temp_doc) """ original_doc = self.document - self.document = original_doc.clone(keep_layers=True) - yield - original_doc.extend(self.document) + self.document = original_doc.clone(keep_layers=keep_layer) + yield self.document self.document = original_doc + + @contextmanager + def expression_variables(self, variables: Dict[str, Any]) -> Generator[None, None, None]: + """Context manager to temporarily set expression variables. + + This context manager is typically used by block processors to temporarily set relevant + expression variables. These variables are deleted or, if pre-existing, restored upon + exiting the context. + + Args: + variables: variables to set + + Example:: + + >>> import vpype_cli + >>> @vpype_cli.cli.command() + ... @vpype_cli.block_processor + ... def run_twice(state, processors): + ... with state.expression_variables({"_first": True}): + ... vpype_cli.execute_processors(processors, state) + ... with state.expression_variables({"_first": False}): + ... vpype_cli.execute_processors(processors, state) + """ + + symtable = self._interpreter.symtable + saved_items = {k: symtable[k] for k in variables if k in symtable} + symtable.update(variables) + yield + for name in variables: + symtable.pop(name) + symtable.update(saved_items) diff --git a/vpype_cli/substitution.py b/vpype_cli/substitution.py new file mode 100644 index 00000000..e8430ccf --- /dev/null +++ b/vpype_cli/substitution.py @@ -0,0 +1,275 @@ +import glob +import os +import pathlib +import sys +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional + +import asteval + +import vpype as vp + +if TYPE_CHECKING: # pragma no cover + from .state import State + + +class PropertySubstitutionError(Exception): + """Error while performing property substitution.""" + + +class ExpressionSubstitutionError(Exception): + """Error while performing expression substitution.""" + + +class _PropertyProxy: + """Helper proxy class to provide access to global and current layer properties. + + Used for :ref:`property substitution ` + using :meth:`str.format_map` and for expression evaluation. + + Either or both global and current layer properties may be configured. If both are enabled, + current layer's properties take precedence over global properties. + + Args: + state: :class:`State` instance + global_prop: access global properties + layer_prop: access current layer properties + """ + + def __init__(self, state: "State", global_prop: bool = True, layer_prop: bool = True): + self._state = state + self._global_prop = global_prop + self._layer_prop = layer_prop + + def _get_prop(self, name) -> Optional[Any]: + if self._state.document is None: + return None + + if ( + self._layer_prop + and self._state.current_layer_id is not None + and self._state.document.exists(self._state.current_layer_id) + and self._state.document.layers[self._state.current_layer_id].property_exists(name) + ): + return self._state.document.layers[self._state.current_layer_id].property(name) + elif self._global_prop and self._state.document.property_exists(name): + return self._state.document.property(name) + else: + return None + + def _set_prop(self, name, value) -> None: + if self._state.document is None or self._layer_prop == self._global_prop: + raise TypeError("cannot set property value (read-only)") + + if self._layer_prop: + if self._state.current_layer_id is None or not self._state.document.exists( + self._state.current_layer_id + ): + raise TypeError("cannot set property value (unknown current layer)") + else: + self._state.document.layers[self._state.current_layer_id].set_property( + name, value + ) + elif self._global_prop: + self._state.document.set_property(name, value) + + def keys(self): + k = set() + if self._global_prop and self._state.document is not None: + k |= self._state.document.metadata.keys() + if ( + self._layer_prop + and self._state.current_layer_id is not None + and self._state.document.exists(self._state.current_layer_id) + ): + k |= self._state.document.layers[self._state.current_layer_id].metadata.keys() + return k + + def __getitem__(self, name): + prop = self._get_prop(name) + if prop is not None: + return prop + else: + raise KeyError(f"property '{name}' not found") + + def __setitem__(self, name, value): + self._set_prop(name, value) + + def __getattr__(self, name): + prop = self._get_prop(name) + if prop is not None: + return prop + else: + raise AttributeError(f"property '{name}' not found") + + def __setattr__(self, name, value): + if name.startswith("_"): + super().__setattr__(name, value) + else: + self._set_prop(name, value) + + +def _split_text( + text: str, prop_interpreter: Callable[[str], str], expr_interpreter: Callable[[str], Any] +) -> Iterable[str]: + """Split input in chunks, applying either the property or expression interpreter based + on markers. + + Args: + text: input to process + prop_interpreter: interpreter for chunks enclosed in curly braces (the braces will be + included in the input provided) + expr_interpreter: interpreter for the chunks enclosed in ``%`` markers (the marker will + *not* be included in the input provided) + + Returns: + generator of processed text chunks + """ + + in_prop = False + in_expr = False + cur_token = "" + + while True: + if len(text) == 0: + if in_expr: + raise ExpressionSubstitutionError( + "unterminated expression substitution pattern" + ) + if in_prop: + raise PropertySubstitutionError("unterminated property substitution pattern") + break + + assert not (in_prop and in_expr) + + s, text = text[0], text[1:] + peek = text[0] if len(text) > 0 else "" + + if s == "{": + if in_prop: + raise PropertySubstitutionError( + "'{' not allowed inside property substitution patterns" + ) + elif in_expr: + cur_token += s + elif peek == "{": + cur_token += s + text = text[1:] + else: + yield cur_token + cur_token = s + in_prop = True + elif s == "}": + if in_prop: + try: + yield str(prop_interpreter(cur_token + s)) + except Exception as exc: + raise PropertySubstitutionError() from exc + cur_token = "" + in_prop = False + elif in_expr: + cur_token += s + elif peek == "}": + cur_token += s + text = text[1:] + else: + raise PropertySubstitutionError("closing '}' without matching '{'") + elif s == "%": + if in_prop: + cur_token += s + elif peek == "%": + cur_token += s + text = text[1:] + elif in_expr: + try: + yield str(expr_interpreter(cur_token)) + except Exception as exc: + raise ExpressionSubstitutionError() from exc + cur_token = "" + in_expr = False + else: + yield cur_token + cur_token = "" + in_expr = True + else: + cur_token += s + + yield cur_token + + +def _substitute_expressions( + text: str, prop_interpreter: Callable[[str], str], expr_interpreter: Callable[[str], Any] +) -> str: + """Apply substitution with custom interpreter functions for property substitution and for + expression substitution. + + Used for testing :func:`_split_text`. + """ + return "".join(_split_text(text, prop_interpreter, expr_interpreter)) + + +def _glob(files: str) -> List[pathlib.Path]: + return [ + pathlib.Path(file) for file in glob.glob(os.path.expandvars(os.path.expanduser(files))) + ] + + +_OS_PATH_SYMBOLS = ( + "abspath", + "basename", + "dirname", + "exists", + "expanduser", + "isfile", + "isdir", + "splitext", +) + + +class SubstitutionHelper: + """Helper class to perform :ref:`property ` and + :ref:`expression ` substitution. + + Args: + state: :class:`State` instance + """ + + def __init__(self, state: "State"): + self._property_proxy = _PropertyProxy(state, True, True) + symtable = { + **vp.UNITS, + **{f: getattr(os.path, f) for f in _OS_PATH_SYMBOLS}, + "input": input, + "glob": _glob, + "convert_length": vp.convert_length, + "convert_angle": vp.convert_angle, + "convert_page_size": vp.convert_page_size, + "stdin": sys.stdin, + "Color": vp.Color, + "prop": self._property_proxy, + "lprop": _PropertyProxy(state, False, True), + "gprop": _PropertyProxy(state, True, False), + } + # disabling numpy as its math functions such as `ceil` do not convert to int. + self._interpreter = asteval.Interpreter( + usersyms=symtable, readonly_symbols=symtable.keys(), use_numpy=False + ) + + @property + def symtable(self) -> Dict[str, Any]: + return self._interpreter.symtable + + def substitute(self, text: str) -> str: + """Apply :ref:`property ` and + :ref:`expression ` substitution. + + Args: + text: user input + + Returns: + fully substituted text + """ + return _substitute_expressions( + text, + lambda s: s.format_map(self._property_proxy), + lambda s: self._interpreter(s, raise_errors=True, show_errors=False), + ) diff --git a/vpype_cli/types.py b/vpype_cli/types.py index 57fd77f0..eb740370 100644 --- a/vpype_cli/types.py +++ b/vpype_cli/types.py @@ -1,5 +1,5 @@ import logging -from typing import ClassVar, List, Optional, Tuple, Union +from typing import Any, ClassVar, List, Optional, Tuple, Type, Union import click @@ -16,9 +16,15 @@ class _DeferredEvaluatorType(click.ParamType): _evaluator_class: ClassVar = _DeferredEvaluator + def __init__(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + def convert(self, value, param, ctx): if isinstance(value, str): - return self.__class__._evaluator_class(value) + return self.__class__._evaluator_class( + value, param.human_readable_name, *self._args, **self._kwargs + ) else: return super().convert(value, param, ctx) @@ -41,7 +47,7 @@ class TextType(_DeferredEvaluatorType): class _TextDeferredEvaluator(_DeferredEvaluator): def evaluate(self, state: "State") -> str: - return state.substitute_input(self._text) + return state.substitute(self._text) name = "text" _evaluator_class = _TextDeferredEvaluator @@ -65,7 +71,7 @@ class IntegerType(_DeferredEvaluatorType): class _IntegerDeferredEvaluator(_DeferredEvaluator): def evaluate(self, state: "State") -> int: - return int(state.substitute_input(self._text)) + return int(state.substitute(self._text)) name = "number" _evaluator_class = _IntegerDeferredEvaluator @@ -95,7 +101,7 @@ class LengthType(_DeferredEvaluatorType): class _LengthDeferredEvaluator(_DeferredEvaluator): def evaluate(self, state: "State") -> float: - return vp.convert_length(state.substitute_input(self._text)) + return vp.convert_length(state.substitute(self._text)) name = "length" _evaluator_class = _LengthDeferredEvaluator @@ -122,7 +128,7 @@ class AngleType(_DeferredEvaluatorType): class _AngleDeferredEvaluator(_DeferredEvaluator): def evaluate(self, state: "State") -> float: - return vp.convert_angle(state.substitute_input(self._text)) + return vp.convert_angle(state.substitute(self._text)) name = "angle" _evaluator_class = _AngleDeferredEvaluator @@ -149,12 +155,64 @@ class PageSizeType(_DeferredEvaluatorType): class _PageSizeDeferredEvaluator(_DeferredEvaluator): def evaluate(self, state: "State") -> Tuple[float, float]: - return vp.convert_page_size(state.substitute_input(self._text)) + return vp.convert_page_size(state.substitute(self._text)) name = "pagesize" _evaluator_class = _PageSizeDeferredEvaluator +class _DelegatedDeferredEvaluatorType(click.ParamType): + """Base class for types which delegate the deferred evaluation to another type class. + + Sub-class will behave like the delegate class (in particular __init__ will accept the same + arguments), but the delegate class will only be created upon deferred evaluation of user + input. + """ + + class _DelegatedDeferredEvaluator(_DeferredEvaluator): + def __init__(self, text: str, param_name: str, cls: Type, *args, **kwargs): + super().__init__(text, param_name) + self._cls = cls + self._args = args + self._kwargs = kwargs + + def evaluate(self, state: "State") -> Any: + delegated = self._cls(*self._args, **self._kwargs) + return delegated.convert(state.substitute(self._text), None, None) + + def __init__(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + + def convert(self, value, param, ctx): + if isinstance(value, str): + return self.__class__._DelegatedDeferredEvaluator( + value, + param.human_readable_name, + self.__class__._delegate_class, + *self._args, + **self._kwargs, + ) + else: + return super().convert(value, param, ctx) + + _delegate_class: ClassVar = click.ParamType + + +class PathType(_DelegatedDeferredEvaluatorType): + """:class:`click.Path` clone which performs substitution on input.""" + + name = "file" + _delegate_class = click.Path + + +class FileType(_DelegatedDeferredEvaluatorType): + """:class:`click.File` clone which performs substitution on input.""" + + name = "file" + _delegate_class = click.File + + def multiple_to_layer_ids( layers: Optional[Union[int, List[int]]], document: vp.Document ) -> List[int]: @@ -201,6 +259,8 @@ def single_to_layer_id( lid = document.free_id() elif layer is None: lid = State.get_current().target_layer_id + elif layer < 1: + raise click.BadParameter(f"layer {layer} is invalid") else: lid = layer @@ -210,7 +270,7 @@ def single_to_layer_id( return lid -class LayerType(click.ParamType): +class LayerType(_DeferredEvaluatorType): """Interpret values of --layer options. If `accept_multiple == True`, comma-separated array of int is accepted or 'all'. Returns @@ -221,64 +281,57 @@ class LayerType(click.ParamType): None is passed through, which typically means to use the default behaviour. """ - name = "layer ID" - NEW = -1 ALL = -2 - def __init__(self, accept_multiple: bool = False, accept_new: bool = False): - self.accept_multiple = accept_multiple - self.accept_new = accept_new - - if accept_multiple: - self.name = "layers" - else: - self.name = "layer" - - def convert(self, value, param, ctx): - # accept value when already converted to final type - if isinstance(value, int): - if value > 0 or value in [self.ALL, self.NEW]: - return value - else: - self.fail(f"inconsistent converted value {value}") - - value = str(value) - if value.lower() == "all": - if self.accept_multiple: - return LayerType.ALL - else: - self.fail( - f"parameter {param.human_readable_name} must be a single layer and does " - "not accept `all`", - param, - ctx, + class _LayerTypeDeferredEvaluator(_DeferredEvaluator): + def __init__( + self, text: str, param_name: str, accept_multiple: bool, accept_new: bool + ): + super().__init__(text, param_name) + self._accept_multiple = accept_multiple + self._accept_new = accept_new + + def evaluate(self, state: "State") -> Union[int, List[int]]: + value = state.substitute(self._text) + + if value.lower() == "all": + if self._accept_multiple: + return LayerType.ALL + else: + raise click.BadParameter( + f"parameter {self._param_name} must be a single layer and does " + "not accept `all`" + ) + elif value.lower() == "new": + if self._accept_new: + return LayerType.NEW + else: + raise click.BadParameter( + f"parameter {self._param_name} must be an existing layer and " + "does not accept `new`" + ) + + try: + if self._accept_multiple: + id_arr = list(map(int, value.split(","))) + for i in id_arr: + if i < 1: + raise click.BadParameter(f"layer {i} is invalid") + return id_arr + else: + return int(value) + except TypeError: + raise click.BadParameter( + f"unexpected {value!r} of type {type(value).__name__}" ) - elif value.lower() == "new": - if self.accept_new: - return LayerType.NEW - else: - self.fail( - f"parameter {param.human_readable_name} must be an existing layer and " - "does not accept `new`", - param, - ctx, + except ValueError: + raise click.BadParameter( + f"{value!r} is not a valid value for parameter {self._param_name}" ) - try: - if self.accept_multiple: - id_arr = list(map(int, value.split(","))) - for i in id_arr: - if i < 1: - raise TypeError - return id_arr - else: - return int(value) - except TypeError: - self.fail(f"unexpected {value!r} of type {type(value).__name__}", param, ctx) - except ValueError: - self.fail( - f"{value!r} is not a valid value for parameter {param.human_readable_name}", - param, - ctx, - ) + def __init__(self, accept_multiple: bool = False, accept_new: bool = False): + super().__init__(accept_multiple=accept_multiple, accept_new=accept_new) + + name = "lid" + _evaluator_class = _LayerTypeDeferredEvaluator diff --git a/vpype_cli/write.py b/vpype_cli/write.py index 9c3f88d9..f5dff92e 100644 --- a/vpype_cli/write.py +++ b/vpype_cli/write.py @@ -9,7 +9,7 @@ from .cli import cli from .decorators import global_processor, pass_state from .state import State -from .types import IntegerType, TextType +from .types import FileType, IntegerType, TextType __all__ = ("write",) @@ -125,7 +125,7 @@ @cli.command(group="Output", help=WRITE_HELP) -@click.argument("output", type=click.File("w")) +@click.argument("output", type=FileType("w")) @click.option( "-f", "--format", @@ -223,7 +223,7 @@ def write( if file_format == "svg": page_size_px = None if page_size: - page_size_px = vp.convert_page_size(state.substitute_input(page_size)) + page_size_px = vp.convert_page_size(state.substitute(page_size)) if landscape: page_size_px = page_size_px[::-1]