# <img src="docs/_static/fileseq_large.png" width="30%" height="30%" title="Fileseq" alt="Fileseq">
[](http://fileseq.readthedocs.io/en/latest/) [](https://github.com/justinfx/fileseq/actions/workflows/ci.yml)
A Python library for parsing frame ranges and file sequences commonly
used in VFX and Animation applications.
## Frame Range Shorthand
Support for:
* Standard: 1-10
* Comma Delimited: 1-10,10-20
* Chunked: 1-100x5
* Filled: 1-100y5
* Staggered: 1-100:3 (1-100x3, 1-100x2, 1-100)
* Negative frame numbers: -10-100
* Subframes: 1001-1066x0.25, 1001.5-1066.0x0.5
* Padding: #=4 padded, @=1 padded
* Alternate padding: #=1 padded, @=1 padded
* Printf Syntax Padding: %04d=4 padded, %01d=1 padded
* Houdini Syntax Padding: $F4=4 padding, $F=1 padded
* Udim Syntax Padding: <UDIM> or %(UDIM)d, always 4 padded
## FrameSets
A FrameSet wraps a sequence of frames in a list container.
### Iterate a FrameSet
```python
fs = fileseq.FrameSet("1-5")
for f in fs:
print(f)
```
### Access Frames
#### Using Indices:
```python
>>> fs = fileseq.FrameSet("1-100:8")
>>> fs[0] # First frame.
1
>>> fs[-1] # Last frame.
98
```
#### Using Convenience Methods:
```python
>>> fs = fileseq.FrameSet("1-100:8")
>>> fs.start() # First frame.
1
>>> fs.end() # Last frame.
98
```
## FileSequence
### Instantiate from String
```python
fileseq.FileSequence("/foo/bar.1-10#.exr")
fileseq.FileSequence("/foo/bar.1-10x0.25#.#.exr", allow_subframes=True)
```
### Format Path for VFX Software
#### Using FileSequence.format Method:
```python
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.exr")
>>> seq.format(template='{dirname}{basename}{padding}{extension}')
"/foo/bar.#.exr"
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.#.exr", allow_subframes=True)
>>> seq.format(template='{dirname}{basename}{padding}{extension}')
"/foo/bar.#.#.exr"
```
#### Joining:
```python
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.exr")
>>> ''.join([seq.dirname(), seq.basename(), '%0{}d'.format(len(str(seq.end()))), seq.extension()])
"/foo/bar.%02d.exr"
```
#### Alternate Padding Styles:
```python
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.exr", pad_style=fileseq.PAD_STYLE_HASH1)
>>> list(seq)
['/foo/bar.1.exr',
'/foo/bar.2.exr',
'/foo/bar.3.exr',
'/foo/bar.4.exr',
'/foo/bar.5.exr',
'/foo/bar.6.exr',
'/foo/bar.7.exr',
'/foo/bar.8.exr',
'/foo/bar.9.exr',
'/foo/bar.10.exr']
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.exr", pad_style=fileseq.PAD_STYLE_HASH4)
>>> list(seq)
['/foo/bar.0001.exr',
'/foo/bar.0002.exr',
'/foo/bar.0003.exr',
'/foo/bar.0004.exr',
'/foo/bar.0005.exr',
'/foo/bar.0006.exr',
'/foo/bar.0007.exr',
'/foo/bar.0008.exr',
'/foo/bar.0009.exr',
'/foo/bar.0010.exr']
```
### Get List of File Paths
```python
>>> seq = fileseq.FileSequence("/foo/bar.1-10#.exr")
>>> [seq[idx] for idx, fr in enumerate(seq.frameSet())]
['/foo/bar.0001.exr',
'/foo/bar.0002.exr',
'/foo/bar.0003.exr',
'/foo/bar.0004.exr',
'/foo/bar.0005.exr',
'/foo/bar.0006.exr',
'/foo/bar.0007.exr',
'/foo/bar.0008.exr',
'/foo/bar.0009.exr',
'/foo/bar.0010.exr']
```
### Get List of File Paths as `pathlib.Path` instances
`fileseq.FilePathSequence` supports the same semantics as `fileseq.FileSequence` but represents result paths as [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html) instances instead of strings.
```python
>>> seq = fileseq.FilePathSequence("/foo/bar.1-10#.exr")
>>> [seq[idx] for idx, fr in enumerate(seq.frameSet())]
[PosixPath('/foo/bar.0001.exr'),
PosixPath('/foo/bar.0002.exr'),
PosixPath('/foo/bar.0003.exr'),
PosixPath('/foo/bar.0004.exr'),
PosixPath('/foo/bar.0005.exr'),
PosixPath('/foo/bar.0006.exr'),
PosixPath('/foo/bar.0007.exr'),
PosixPath('/foo/bar.0008.exr'),
PosixPath('/foo/bar.0009.exr'),
PosixPath('/foo/bar.0010.exr')]
```
## Finding Sequences on Disk
### Check a Directory for All Existing Sequences
```python
seqs = fileseq.findSequencesOnDisk("/show/shot/renders/bty_foo/v1")
```
Or, to get results as `pathlib.Path`, use the `FilePathSequence` classmethod:
```python
seqs = fileseq.FilePathSequence.findSequencesOnDisk("/show/shot/renders/bty_foo/v1")
```
### Check a Directory for One Existing Sequence.
* Use a '@' or '#' where you might expect to use '*' for a wildcard character.
* For this method, it doesn't matter how many instances of the padding character you use, it will still find your sequence.
Yes:
```python
fileseq.findSequenceOnDisk('/foo/bar.@.exr')
```
Yes:
```python
fileseq.findSequenceOnDisk('/foo/bar.@@@@@.exr')
```
No:
```python
fileseq.findSequenceOnDisk('/foo/bar.*.exr')
```
* To find subframe sequences you must explicitly opt-in
```python
fileseq.findSequenceOnDisk('/foo/bar.#.#.exr', allow_subframes=True)
```
## Limitations
While there may be many custom types of sequence patterns that could be considered a valid pipeline format, this library has
taken an opinionated stance on acceptable sequence formats. This is done to keep parsing rules manageable and to not
over-complicate the logic. The parsing rules can and have been expanded in some ways over time, such as adding support
for new padding format patterns like printf "%04d", houdini "$F" and "<UDIM>". But other rules remain the same, such as expecting
a frame number component to be found just before the file extension component.
## Language Ports
* Go: https://github.com/justinfx/gofileseq
* C++: https://github.com/justinfx/gofileseq/tree/master/cpp
Raw data
{
"_id": null,
"home_page": "https://github.com/justinfx/fileseq",
"name": "Fileseq",
"maintainer": "Justin Israel",
"docs_url": "https://pythonhosted.org/Fileseq/",
"requires_python": null,
"maintainer_email": "justinisrael@gmail.com",
"keywords": "vfx visual effects file sequence frames image",
"author": "Matt Chambers",
"author_email": "yougotrooted@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/c1/ae/053f3882a2ed7e19737372fb3876aad7eeb79334285e9ee05545acfc4d08/fileseq-2.2.1.tar.gz",
"platform": null,
"description": "# <img src=\"docs/_static/fileseq_large.png\" width=\"30%\" height=\"30%\" title=\"Fileseq\" alt=\"Fileseq\">\n\n[](http://fileseq.readthedocs.io/en/latest/) [](https://github.com/justinfx/fileseq/actions/workflows/ci.yml)\n\nA Python library for parsing frame ranges and file sequences commonly \nused in VFX and Animation applications.\n\n## Frame Range Shorthand\n\nSupport for:\n\n* Standard: 1-10\n* Comma Delimited: 1-10,10-20\n* Chunked: 1-100x5\n* Filled: 1-100y5\n* Staggered: 1-100:3 (1-100x3, 1-100x2, 1-100)\n* Negative frame numbers: -10-100\n* Subframes: 1001-1066x0.25, 1001.5-1066.0x0.5\n* Padding: #=4 padded, @=1 padded\n* Alternate padding: #=1 padded, @=1 padded\n* Printf Syntax Padding: %04d=4 padded, %01d=1 padded\n* Houdini Syntax Padding: $F4=4 padding, $F=1 padded\n* Udim Syntax Padding: <UDIM> or %(UDIM)d, always 4 padded\n\n\n## FrameSets\n\nA FrameSet wraps a sequence of frames in a list container.\n\n### Iterate a FrameSet\n```python\nfs = fileseq.FrameSet(\"1-5\")\nfor f in fs:\n print(f)\n```\n\n### Access Frames\n\n#### Using Indices:\n```python\n>>> fs = fileseq.FrameSet(\"1-100:8\")\n>>> fs[0] # First frame.\n1\n>>> fs[-1] # Last frame.\n98\n```\n\n#### Using Convenience Methods:\n```python\n>>> fs = fileseq.FrameSet(\"1-100:8\")\n>>> fs.start() # First frame.\n1\n>>> fs.end() # Last frame.\n98\n```\n\n## FileSequence\n\n### Instantiate from String\n```python\nfileseq.FileSequence(\"/foo/bar.1-10#.exr\")\nfileseq.FileSequence(\"/foo/bar.1-10x0.25#.#.exr\", allow_subframes=True)\n```\n\n### Format Path for VFX Software\n\n#### Using FileSequence.format Method:\n```python\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.exr\")\n>>> seq.format(template='{dirname}{basename}{padding}{extension}') \n\"/foo/bar.#.exr\"\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.#.exr\", allow_subframes=True)\n>>> seq.format(template='{dirname}{basename}{padding}{extension}')\n\"/foo/bar.#.#.exr\"\n```\n\n#### Joining:\n```python\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.exr\")\n>>> ''.join([seq.dirname(), seq.basename(), '%0{}d'.format(len(str(seq.end()))), seq.extension()])\n\"/foo/bar.%02d.exr\"\n```\n\n#### Alternate Padding Styles:\n```python\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.exr\", pad_style=fileseq.PAD_STYLE_HASH1)\n>>> list(seq)\n['/foo/bar.1.exr',\n '/foo/bar.2.exr',\n '/foo/bar.3.exr',\n '/foo/bar.4.exr',\n '/foo/bar.5.exr',\n '/foo/bar.6.exr',\n '/foo/bar.7.exr',\n '/foo/bar.8.exr',\n '/foo/bar.9.exr',\n '/foo/bar.10.exr']\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.exr\", pad_style=fileseq.PAD_STYLE_HASH4)\n>>> list(seq)\n['/foo/bar.0001.exr',\n '/foo/bar.0002.exr',\n '/foo/bar.0003.exr',\n '/foo/bar.0004.exr',\n '/foo/bar.0005.exr',\n '/foo/bar.0006.exr',\n '/foo/bar.0007.exr',\n '/foo/bar.0008.exr',\n '/foo/bar.0009.exr',\n '/foo/bar.0010.exr']\n```\n\n### Get List of File Paths\n```python\n>>> seq = fileseq.FileSequence(\"/foo/bar.1-10#.exr\")\n>>> [seq[idx] for idx, fr in enumerate(seq.frameSet())]\n['/foo/bar.0001.exr',\n '/foo/bar.0002.exr',\n '/foo/bar.0003.exr',\n '/foo/bar.0004.exr',\n '/foo/bar.0005.exr',\n '/foo/bar.0006.exr',\n '/foo/bar.0007.exr',\n '/foo/bar.0008.exr',\n '/foo/bar.0009.exr',\n '/foo/bar.0010.exr']\n```\n\n### Get List of File Paths as `pathlib.Path` instances\n`fileseq.FilePathSequence` supports the same semantics as `fileseq.FileSequence` but represents result paths as [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html) instances instead of strings.\n\n```python\n>>> seq = fileseq.FilePathSequence(\"/foo/bar.1-10#.exr\")\n>>> [seq[idx] for idx, fr in enumerate(seq.frameSet())]\n[PosixPath('/foo/bar.0001.exr'),\n PosixPath('/foo/bar.0002.exr'),\n PosixPath('/foo/bar.0003.exr'),\n PosixPath('/foo/bar.0004.exr'),\n PosixPath('/foo/bar.0005.exr'),\n PosixPath('/foo/bar.0006.exr'),\n PosixPath('/foo/bar.0007.exr'),\n PosixPath('/foo/bar.0008.exr'),\n PosixPath('/foo/bar.0009.exr'),\n PosixPath('/foo/bar.0010.exr')]\n```\n\n## Finding Sequences on Disk\n\n### Check a Directory for All Existing Sequences\n```python\nseqs = fileseq.findSequencesOnDisk(\"/show/shot/renders/bty_foo/v1\")\n```\n\nOr, to get results as `pathlib.Path`, use the `FilePathSequence` classmethod:\n\n```python\nseqs = fileseq.FilePathSequence.findSequencesOnDisk(\"/show/shot/renders/bty_foo/v1\")\n```\n\n### Check a Directory for One Existing Sequence.\n* Use a '@' or '#' where you might expect to use '*' for a wildcard character. \n* For this method, it doesn't matter how many instances of the padding character you use, it will still find your sequence.\n\nYes:\n```python\nfileseq.findSequenceOnDisk('/foo/bar.@.exr')\n```\nYes:\n```python\nfileseq.findSequenceOnDisk('/foo/bar.@@@@@.exr')\n```\nNo: \n```python\nfileseq.findSequenceOnDisk('/foo/bar.*.exr')\n```\n\n* To find subframe sequences you must explicitly opt-in\n```python\nfileseq.findSequenceOnDisk('/foo/bar.#.#.exr', allow_subframes=True)\n```\n\n## Limitations\n\nWhile there may be many custom types of sequence patterns that could be considered a valid pipeline format, this library has \ntaken an opinionated stance on acceptable sequence formats. This is done to keep parsing rules manageable and to not \nover-complicate the logic. The parsing rules can and have been expanded in some ways over time, such as adding support\nfor new padding format patterns like printf \"%04d\", houdini \"$F\" and \"<UDIM>\". But other rules remain the same, such as expecting\na frame number component to be found just before the file extension component.\n\n## Language Ports\n\n* Go: https://github.com/justinfx/gofileseq\n* C++: https://github.com/justinfx/gofileseq/tree/master/cpp\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python library for parsing frame ranges and file sequences commonly used in VFX and Animation applications.",
"version": "2.2.1",
"project_urls": {
"Homepage": "https://github.com/justinfx/fileseq"
},
"split_keywords": [
"vfx",
"visual",
"effects",
"file",
"sequence",
"frames",
"image"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1d8d3f924a7c2ae22c3c658e8907ceac28a5582eeefad35af1d2f67031d45bfd",
"md5": "7b1e54d48296fd3eba4ae75dd965844b",
"sha256": "b3da606214ef263b6e0f44affb05277f6bd24eb68fc4e3823203ed77511febea"
},
"downloads": -1,
"filename": "fileseq-2.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7b1e54d48296fd3eba4ae75dd965844b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 37100,
"upload_time": "2025-10-27T00:44:15",
"upload_time_iso_8601": "2025-10-27T00:44:15.913142Z",
"url": "https://files.pythonhosted.org/packages/1d/8d/3f924a7c2ae22c3c658e8907ceac28a5582eeefad35af1d2f67031d45bfd/fileseq-2.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c1ae053f3882a2ed7e19737372fb3876aad7eeb79334285e9ee05545acfc4d08",
"md5": "276c59399716af1d5f9f8a642a8909b7",
"sha256": "f63bdbbca3d647c441097e07909e11ff3a3b2ea600eee9e31b624cced566661c"
},
"downloads": -1,
"filename": "fileseq-2.2.1.tar.gz",
"has_sig": false,
"md5_digest": "276c59399716af1d5f9f8a642a8909b7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 61311,
"upload_time": "2025-10-27T00:44:17",
"upload_time_iso_8601": "2025-10-27T00:44:17.099047Z",
"url": "https://files.pythonhosted.org/packages/c1/ae/053f3882a2ed7e19737372fb3876aad7eeb79334285e9ee05545acfc4d08/fileseq-2.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-27 00:44:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "justinfx",
"github_project": "fileseq",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "pytest",
"specs": []
},
{
"name": "pylint",
"specs": []
},
{
"name": "flake8",
"specs": []
},
{
"name": "sphinx",
"specs": []
},
{
"name": "sphinx-rtd-theme",
"specs": []
}
],
"lcname": "fileseq"
}