1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
|
PySeq
=====
PySeq is a python module that finds groups of items that follow a naming
convention containing a numerical sequence index (e.g. fileA.001.png,
fileA.002.png, fileA.003.png...) and serializes them into a compressed sequence
string representing the entire sequence (e.g. fileA.1-3.png). It should work
regardless of where the numerical sequence index is embedded in the name. For
examples, see basic usage below or http://rsgalloway.github.io/pyseq
[Installation](#installation) |
[Basic Usage](#basic-usage) |
[API Examples](#api-examples) |
[Formatting](#formatting) |
[Command-Line Tools](#command-line-tools) |
[Frame Patterns](#frame-patterns) |
[Testing](#testing)
## Installation
The easiest way to install pyseq:
```bash
$ pip install -U pyseq
```
#### Environment
PySeq uses [envstack](https://github.com/rsgalloway/envstack) to externalize
settings and looks for a `pyseq.env` file to source environment variables:
```bash
$ pip install -U envstack
$ ./pyseq.env -r
PYSEQ_FRAME_PATTERN=\d+
PYSEQ_GLOBAL_FORMAT=%4l %h%p%t %R
PYSEQ_RANGE_SEP=,
PYSEQ_STRICT_PAD=0
```
#### Distribution
If installing from source you can use [distman](https://github.com/rsgalloway/distman)
to install PySeq using the provided `dist.json` file:
```bash
$ pip install -U distman
$ distman [-d]
```
Using distman will deploy the targets defined in the `dist.json` file to the
root folder defined by `${DEPLOY_ROOT}`:
## Basic Usage
Using the "z1" file sequence example in the "tests" directory, we start by
listing the directory contents using `ls`:
```bash
$ ls tests/files/z1*
tests/files/z1_001_v1.1.png tests/files/z1_001_v1.4.png tests/files/z1_002_v1.3.png tests/files/z1_002_v2.11.png
tests/files/z1_001_v1.2.png tests/files/z1_002_v1.1.png tests/files/z1_002_v1.4.png tests/files/z1_002_v2.12.png
tests/files/z1_001_v1.3.png tests/files/z1_002_v1.2.png tests/files/z1_002_v2.10.png tests/files/z1_002_v2.9.png
```
Now we list the same directory contents using `lss`, which will find the
sequences and display them in the default compressed format:
```bash
$ lss tests/files/z1*
4 z1_001_v1.%d.png [1-4]
4 z1_002_v1.%d.png [1-4]
4 z1_002_v2.%d.png [9-12]
```
Recursivly walk a folder and find all the sequences:
```bash
$ lss -r tests
tests
├── test_pyseq.py
└── files
├── 012_vb_110_v001.1-10.png
├── 012_vb_110_v002.1-10.png
├── a.1-14.tga
├── alpha.txt
├── bnc01_TinkSO_tx_0_ty_0.101-105.tif
├── bnc01_TinkSO_tx_0_ty_1.101-105.tif
├── bnc01_TinkSO_tx_1_ty_0.101-105.tif
├── bnc01_TinkSO_tx_1_ty_1.101-105.tif
├── file.1-99.tif
├── file.info.03.rgb
├── file01.1-4.j2k
├── file01_40-43.rgb
├── file02_44-47.rgb
├── file1-4.03.rgb
├── fileA.1-3.jpg
├── fileA.1-3.png
├── file_02.tif
├── z1_001_v1.1-4.png
├── z1_002_v1.1-4.png
└── z1_002_v2.9-12.png
```
Piping the output of `find` to `lss`, for example finding all the png sequences:
```bash
$ find ./tests/ -name *.png | lss
10 012_vb_110_v001.%04d.png [1-10]
10 012_vb_110_v002.%04d.png [1-10]
3 fileA.%04d.png [1-3]
4 z1_001_v1.%d.png [1-4]
4 z1_002_v1.%d.png [1-4]
4 z1_002_v2.%d.png [9-12]
```
Use the `--format` option to retain the relative path:
```bash
$ find tests/ -name "*.png" | lss -f "%D%h%r%t"
tests/files/012_vb_110_v001.1-10.png
tests/files/012_vb_110_v002.1-10.png
tests/files/fileA.1-3.png
tests/files/z1_001_v1.1-4.png
tests/files/z1_002_v1.1-4.png
tests/files/z1_002_v2.9-12.png
```
## API Examples
Compression, or serialization, of lists of items:
```python
>>> s = Sequence(['file.0001.jpg', 'file.0002.jpg', 'file.0003.jpg'])
>>> print(s)
file.1-3.jpg
>>> s.append('file.0006.jpg')
>>> print(s.format("%h%p%t %R"))
file.%04d.jpg [1-3, 6]
```
Uncompression, or deserialization, of compressed sequences strings:
```python
>>> s = uncompress('./tests/012_vb_110_v001.%04d.png 1-1001', fmt='%h%p%t %r')
>>> len(s)
1001
>>> print(s.format('%04l %h%p%t %R'))
1001 012_vb_110_v001.%04d.png [1-1001]
```
Walk a directory tree and print disk usage for file sequences:
```python
>>> for root, dirs, seqs in pyseq.walk(folder):
... for seq in seqs:
... print(seq.format("%h%r%t %H"))
012_vb_110_v001.1000-1321.exr 123.5G
012_vb_110_v002.1000-1163.exr 40.2G
012_vb_110_v003.1000-1027.exr 72.2G
```
## Formatting
The following directives can be embedded in the format string.
| Directive | Meaning |
|-----------|--------------------------------------|
| `%s` | sequence start |
| `%e` | sequence end |
| `%l` | sequence length |
| `%f` | list of found files |
| `%m` | list of missing files |
| `%M` | explicit missing files [11-14,19-21] |
| `%p` | padding, e.g. %06d |
| `%r` | implied range, start-end |
| `%R` | explicit broken range, [1-10, 15-20] |
| `%d` | disk usage |
| `%H` | disk usage (human readable) |
| `%D` | parent directory |
| `%h` | string preceding sequence number |
| `%t` | string after the sequence number |
Here are some examples using `lss -f <format>` and `seq.format(..)`:
Using `lss -f <format>`:
```bash
$ lss tests/files/a*.tga -f "%h%r%t"
a.1-14.tga
$ lss tests/files/a*.tga -f "%l %h%r%t"
7 a.1-14.tga
$ lss tests/files/a*.tga -f "%l %h%r%t %M"
7 a.1-14.tga [4-9, 11]
```
In Python, using `seq.format(..)`:
```python
>>> s = pyseq.get_sequences("tests/files/a*.tga")[0]
>>> print(s.format("%h%r%t"))
a.1-14.tga
>>> print(s.format("%l %h%r%t"))
7 a.1-14.tga
>>> print(s.format("%l %h%r%t %M"))
7 a.1-14.tga [4-9, 11]
```
## Command-Line Tools
PySeq comes with the following sequence-aware command-line tools:
| Command | Description | Example Usage |
| ------- | ------------------------------------- | -------------------------------- |
| `lss` | List image sequences in a directory | `lss shots/` |
| `stree` | Display sequence-aware directory tree | `stree shots/` |
| `sfind` | Recursively find image sequences | `sfind assets/ -name "*.exr"` |
| `sdiff` | Compare two sequences | `sdiff A.%04d.exr B.%04d.exr` |
| `sstat` | Print detailed stats about a sequence | `sstat render.%04d.exr` |
| `scopy` | Copy a sequence to another directory | `scopy a.%04d.exr /tmp/output/` |
| `smove` | Move a sequence to another directory | `smove b.%04d.exr /tmp/archive/` |
Example commands:
```bash
# List sequences in a folder
$ lss tests/files
# Show directory structure with grouped sequences
$ stree tests/
# Find all .png sequences recursively
$ sfind ./tests -name "*.png"
# Compare two sequences and print diffs
$ sdiff comp_A.%04d.exr comp_B.%04d.exr
# Show stats for a sequence
$ sstat render.%04d.exr
$ sstat --json render.%04d.exr
# Copy a sequence and rename it
$ scopy input.%04d.exr output/ --rename scene01
# Move and renumber a sequence starting at frame 1001
$ smove old.%04d.exr archive/ --renumber 1001
```
## Frame Patterns
The environment var `${PYSEQ_FRAME_PATTERN}` can be used to define custom regex
patterns for identifying frame numbers. For example if frames are always preceded
with an _, you might use:
```bash
$ export PYSEQ_FRAME_PATTERN="_\d+"
```
Environment vars can be defined anywhere in your environment, or if using
[envstack](https://github.com/rsgalloway/envstack) add it to the
`pyseq.env` file and make sure it's found in `${ENVPATH}`:
```bash
$ export ENVPATH=/path/to/env/files
```
Examples of regex patterns can be found in the `pyseq.env` file:
```yaml
# matches all numbers, the most flexible
PYSEQ_FRAME_PATTERN: \d+
# excludes version numbers, e.g. file_v001.1001.exr
PYSEQ_FRAME_PATTERN: ([^v\d])\d+
# frame numbers are dot-delimited, e.g. file.v1.1001.exr
PYSEQ_FRAME_PATTERN: \.\d+\.
# frame numbers start with an underscore, e.g. file_v1_1001.exr
PYSEQ_FRAME_PATTERN: _\d+
```
## Testing
To run the unit tests, simply run `pytest` in a shell:
```bash
$ pytest tests/
```
|