Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: tests

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
python-version: "3.8"
- os: ubuntu-latest
python-version: "3.9"
- os: ubuntu-latest
python-version: "3.10"
- os: ubuntu-latest
python-version: "3.11"
- os: ubuntu-latest
python-version: "3.12"
- os: ubuntu-latest
python-version: "3.13"
- os: macos-latest
python-version: "3.11"
- os: macos-latest
python-version: "3.13"
- os: windows-latest
python-version: "3.11"
- os: windows-latest
python-version: "3.13"

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install package and test dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".[dev]"

- name: Run test suite
run: python -m pytest tests/ -q
10 changes: 10 additions & 0 deletions CHANGELOG → CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
CHANGELOG
=========

## 0.9.1

* Removes the envstack runtime dependency and migrates packaging metadata to `pyproject.toml`
* Adds GitHub Actions test coverage across Python 3.8+ and multiple operating systems
* Tests installed console script entry points instead of relying on repo wrapper scripts
* Resolves issue #88 by handling `KeyboardInterrupt` cleanly across CLI commands
* Resolves issue #89 by fixing `Sequence.contains()` false positives with unrelated numbers
* Improves Windows compatibility in tests and CLI output handling
* Miscellaneous test and documentation cleanup

## 0.9.0

* Adds initial versions of pyseq aware cli tools
Expand Down
21 changes: 6 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ examples, see basic usage below or http://rsgalloway.github.io/pyseq
[Frame Patterns](#frame-patterns) |
[Testing](#testing)


## Installation

The easiest way to install pyseq:
Expand All @@ -27,17 +26,9 @@ $ 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
```
PySeq reads configuration from standard environment variables. The repository
includes a `pyseq.env` example [envstack](https://github.com/rsgalloway/envstack)
file for users who want to manage those variables externally.

#### Distribution

Expand Down Expand Up @@ -258,8 +249,8 @@ $ 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}`:
`envstack`, add them to `pyseq.env` and make sure that file is found in
`${ENVPATH}`:

```bash
$ export ENVPATH=/path/to/env/files
Expand All @@ -286,5 +277,5 @@ PYSEQ_FRAME_PATTERN: _\d+
To run the unit tests, simply run `pytest` in a shell:

```bash
$ pytest tests/
$ pytest tests -q
```
2 changes: 1 addition & 1 deletion bin/lss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/scopy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/sdiff
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/sfind
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/smove
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/sstat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
2 changes: 1 addition & 1 deletion bin/stree
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (c) 2011-2025, Ryan Galloway (ryan@rsgalloway.com)
#
Expand Down
58 changes: 3 additions & 55 deletions dist.json
Original file line number Diff line number Diff line change
@@ -1,61 +1,9 @@
{
"author": "ryan@rsg.io",
"targets": {
"lss": {
"source": "bin/lss",
"destination": "{DEPLOY_ROOT}/bin/lss"
},
"lss.bat": {
"source": "bin/lss.bat",
"destination": "{DEPLOY_ROOT}/bin/lss.bat"
},
"scopy": {
"source": "bin/scopy",
"destination": "{DEPLOY_ROOT}/bin/scopy"
},
"scopy.bat": {
"source": "bin/scopy.bat",
"destination": "{DEPLOY_ROOT}/bin/scopy.bat"
},
"sdiff": {
"source": "bin/sdiff",
"destination": "{DEPLOY_ROOT}/bin/sdiff"
},
"sdiff.bat": {
"source": "bin/sdiff.bat",
"destination": "{DEPLOY_ROOT}/bin/sdiff.bat"
},
"sfind": {
"source": "bin/sfind",
"destination": "{DEPLOY_ROOT}/bin/sfind"
},
"sfind.bat": {
"source": "bin/sfind.bat",
"destination": "{DEPLOY_ROOT}/bin/sfind.bat"
},
"smove": {
"source": "bin/smove",
"destination": "{DEPLOY_ROOT}/bin/smove"
},
"smove.bat": {
"source": "bin/smove.bat",
"destination": "{DEPLOY_ROOT}/bin/smove.bat"
},
"sstat": {
"source": "bin/sstat",
"destination": "{DEPLOY_ROOT}/bin/sstat"
},
"sstat.bat": {
"source": "bin/sstat.bat",
"destination": "{DEPLOY_ROOT}/bin/sstat.bat"
},
"stree": {
"source": "bin/stree",
"destination": "{DEPLOY_ROOT}/bin/stree"
},
"stree.bat": {
"source": "bin/stree.bat",
"destination": "{DEPLOY_ROOT}/bin/stree.bat"
"bin": {
"source": "bin/*",
"destination": "{DEPLOY_ROOT}/bin/%1"
},
"lib": {
"source": "lib/pyseq",
Expand Down
9 changes: 1 addition & 8 deletions lib/pyseq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,6 @@
"""

__author__ = "Ryan Galloway"
__version__ = "0.9.0"

try:
import envstack

envstack.init("pyseq")
except Exception:
pass
__version__ = "0.9.1"

from .seq import *
2 changes: 2 additions & 0 deletions lib/pyseq/lss.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

from pyseq import __version__, get_sequences
from pyseq import seq as pyseq
from pyseq.util import cli_catch_keyboard_interrupt
from pyseq import walk


Expand Down Expand Up @@ -110,6 +111,7 @@ def _recur_cb(option: Any, opt_str: str, value: Optional[str], parser: Any):
setattr(parser.values, option.dest, value)


@cli_catch_keyboard_interrupt
def main():
"""Command-line interface."""

Expand Down
7 changes: 6 additions & 1 deletion lib/pyseq/scopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
from typing import Optional

import pyseq
from pyseq.util import is_compressed_format_string, resolve_sequence
from pyseq.util import (
cli_catch_keyboard_interrupt,
is_compressed_format_string,
resolve_sequence,
)


def copy_sequence(
Expand Down Expand Up @@ -91,6 +95,7 @@ def copy_sequence(
shutil.copy2(src_path, dest_path)


@cli_catch_keyboard_interrupt
def main():
"""Main function to parse cli args and copy sequences."""

Expand Down
2 changes: 2 additions & 0 deletions lib/pyseq/sdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import sys

import pyseq
from pyseq.util import cli_catch_keyboard_interrupt
from pyseq.util import resolve_sequence


Expand Down Expand Up @@ -113,6 +114,7 @@ def show(label: str, a: str, b: str):
print(f"Disk usage mismatch:\n A: {a}\n B: {b}")


@cli_catch_keyboard_interrupt
def main():
"""Main function to parse arguments and display sequence diffs."""

Expand Down
42 changes: 37 additions & 5 deletions lib/pyseq/seq.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,13 +663,45 @@ def includes(self, item: Union[str, Item]):
if not isinstance(item, Item):
item = Item(item)

if self[-1] != item:
return self[-1].is_sibling(item)
elif self[0] != item:
return self[0].is_sibling(item)
elif self[0] == item:
if self[-1] == item:
item.frame = self[-1].frame
item.pad = self[-1].pad
item.head = self[-1].head
item.tail = self[-1].tail
return True

if self[0] == item:
item.frame = self[0].frame
item.pad = self[0].pad
item.head = self[0].head
item.tail = self[0].tail
return True

if len(self) == 1:
return self[0].is_sibling(item)

# Compare against cloned anchors so membership checks do not mutate the
# cached frame metadata on items already stored in the sequence.
canonical_head = self[0].head
canonical_tail = self[0].tail

anchors = []
for member in (self[-1], self[0]):
if anchors and member == self[-1] == self[0]:
continue
anchor = Item(member)
anchor.frame = member.frame
anchor.pad = member.pad
anchor.head = member.head
anchor.tail = member.tail
anchors.append(anchor)

for anchor in anchors:
if anchor.is_sibling(item):
return item.name.startswith(canonical_head) and item.name.endswith(
canonical_tail
)

return False

def contains(self, item: Item):
Expand Down
2 changes: 2 additions & 0 deletions lib/pyseq/sfind.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import sys

import pyseq
from pyseq.util import cli_catch_keyboard_interrupt


def walk_and_collect_sequences(
Expand All @@ -59,6 +60,7 @@ def walk_and_collect_sequences(
yield os.path.join(dirpath, full_str)


@cli_catch_keyboard_interrupt
def main():
"""Main function to parse arguments and call the sequence finder."""

Expand Down
7 changes: 6 additions & 1 deletion lib/pyseq/smove.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
from typing import Optional

import pyseq
from pyseq.util import is_compressed_format_string, resolve_sequence
from pyseq.util import (
cli_catch_keyboard_interrupt,
is_compressed_format_string,
resolve_sequence,
)


def move_sequence(
Expand Down Expand Up @@ -91,6 +95,7 @@ def move_sequence(
shutil.move(src_path, dest_path)


@cli_catch_keyboard_interrupt
def main():
"""Main function to handle command line arguments and call the move_sequence."""

Expand Down
Loading
Loading