About
This is the v2.1.0 release of **simfile** for Python 3. This is a feature release primarily focused on new abstractions around filesystem traversal & asset discovery for simfiles. It also includes some critical bugfixes & significant performance boosts, mostly by upgrading **[msdparser](https://msdparser.readthedocs.io/)** to its new major release v2.0.0.
Up-to-date documentation for this release can be found on **[simfile.readthedocs.io](https://simfile.readthedocs.io/en/main/)**.
Filesystem traversal
The new [simfile.dir](https://simfile.readthedocs.io/en/main/autoapi/simfile/dir/index.html#module-simfile.dir) module offers [SimfileDirectory](https://simfile.readthedocs.io/en/main/autoapi/simfile/dir/index.html#simfile.dir.SimfileDirectory) and [SimfilePack](https://simfile.readthedocs.io/en/main/autoapi/simfile/dir/index.html#simfile.dir.SimfilePack) classes for nagivating simfile filesystem structures:
python
from simfile.dir import SimfilePack
pack = SimfilePack(R"C:\StepMania\Songs\My Pack")
for simfile_dir in pack.simfile_dirs():
print("Simfile paths: ", simfile_dir.sm_path, simfile_dir.ssc_path)
sim = simfile_dir.open()
print("Title:", sim.title)
Additionally, the top-level [simfile](https://simfile.readthedocs.io/en/main/autoapi/simfile/index.html#module-simfile) module now offers [opendir()](https://simfile.readthedocs.io/en/main/autoapi/simfile/index.html#simfile.opendir) and [openpack()](https://simfile.readthedocs.io/en/main/autoapi/simfile/index.html#simfile.openpack) functions as simplified interfaces to the simfile.dir API:
python
import simfile
for sim, filename in simfile.openpack(R"C:\StepMania\Songs\My Pack"):
print(f"Loaded {sim.title} from {filename}")
These new features aren't limited to the OS filesystem, either. **[PyFilesystem2](https://docs.pyfilesystem.org/en/latest/index.html)** has been integrated throughout this library’s filesystem interactions, enabling OS and non-OS filesystems to be traversed using the same code. All functions, methods, and constructors that lead to filesystem interactions now have an optional `filesystem` parameter for specifying a PyFS filesystem object. When omitted, the filesystem defaults to the native OS filesystem as before.
This means you can open a ZIP file (or [any other supported filesystem](https://docs.pyfilesystem.org/en/latest/builtin.html)) as a SimfileDirectory or SimfilePack, without needing to extract to disk:
python
import simfile
from fs.zipfs import ZipFS
zip_fs = ZipFS(R"C:\Users\micro\Downloads\Coconut [13].zip")
sim, filename = simfile.opendir("Coconut", filesystem=zip_fs)
print(f"Loaded {sim.title} from {filename} inside ZIP")
Asset discovery
The new [simfile.assets](https://simfile.readthedocs.io/en/main/autoapi/simfile/assets/index.html#module-simfile.assets) module provides an [Assets](https://simfile.readthedocs.io/en/main/autoapi/simfile/assets/index.html#simfile.assets.Assets) class that can reliably discover paths to simfile assets, even if they’re not specified in the simfile. This functionality is also accessible through SimfileDirectory's [assets()](https://simfile.readthedocs.io/en/main/autoapi/simfile/dir/index.html#simfile.dir.SimfileDirectory.assets) method.
python
from simfile.dir import SimfileDirectory
simfile_dir = SimfileDirectory(R"C:\StepMania\Songs\My Pack\My Song")
assets = simfile_dir.assets()
assert assets.music, "No music file"
with open(assets.music, "rb") as audio_file:
...
Assets include the song file (`music`) and graphics files (`banner`, `background`, `cdtitle`, `jacket`, `cdimage`, `disc`). All paths are absolute and normalized, and they should match the assets loaded by StepMania in virtually all cases.
DisplayBPM ergonomics
The [DisplayBPM](https://simfile.readthedocs.io/en/main/autoapi/simfile/timing/displaybpm/index.html#simfile.timing.displaybpm.DisplayBPM) classes now all expose the same four properties; the ones that don’t apply to a particular class return None. This enables you to handle all three cases without having to import the types for `isinstance` checks. Refer to "[Getting the displayed BPM](https://simfile.readthedocs.io/en/main/timing-note-data.html#getting-the-displayed-bpm)" for more details.
msdparser upgrade
**simfile**'s dependency on **[msdparser](https://msdparser.readthedocs.io/)** has been upgraded to v2.0.0, a major release that corrects how backslashes `\` and colons `:` are parsed. These fixes apply to both reading and writing simfiles. From the perspective of client code, all you need to know is that the values you get are always **unescaped**: `#TITLE:rE\:Voltagers;` parses to a `title` property with value `rE:Voltagers`, and serializing it back to MSD adds the necessary `\` before the colon in the title automatically.
Additionally, **msdparser** v2.0.0 parses large documents up to 10 times faster than before!
Note: if you get dependency errors when trying to upgrade **simfile**, try removing **msdparser** as an explicit dependency to allow it to cross the major version.
Miscellaneous bugfixes
* The `charts` property on simfiles is now writable, meaning the list of charts can be overwritten directly (not just added to / removed from).
* [sm_to_ssc()](https://simfile.readthedocs.io/en/main/autoapi/simfile/convert/index.html#simfile.convert.sm_to_ssc) no longer produces invalid output when there are negative BPMs or stops in the timing data. (It throws `NotImplementedError` as a temporary stopgap. In the future, negative timing data will be converted to warps, as StepMania does automatically.)
* Various type annotations have been improved throughout the library. In particular, `Iterator` input arguments have been replaced with `Iterable` so that you don’t need to wrap them in `iter(...)` to suppress type errors from static analyzers.
Documentation
In addition to tutorials & API docs, now you can [learn by example](https://simfile.readthedocs.io/en/main/examples.html)! This page provides recipes & full scripts that demonstrate correct & type-checked library usage.
Many other pages & API docstrings were updated for clarity & precision.
---
Questions?
Use the [Discussions](https://github.com/garcia/simfile/discussions) tab in this repository if you have questions about how to use the **simfile** library or ideas for new features! Holding these discussions on the open web fosters communication across a broader community of open-source enthusiasts than Discord can offer.
Credits
Thanks to bkirz, telperion, and an anonymous contributor for their input on the API additions & enhancements for this release.
This project wouldn't exist were it not for the free creative work of hundreds of stepartists & open-source software enthusiasts. Thank you very much for your best dance!