Changelog
v3.0.0a4
LineEndingsno longer clobbers newly-written values to simfiles. Previously, it treated the original MSD parameter as canonical (it is not).The
strictparameter finally defaults toFalseas originally planned.
v3.0.0a3
v3.0.0a2
New features
A new module, simfile.tidy, is now available.
This module offers one function, tidy(),
that acts as the interface to various behaviors
which normalize a chart’s serialized representation.
It also offers some presets that package these behaviors together.
Miscellaneous
Duplicate keys are now preserved, although they are not accessible through simfile / chart attributes. They are stored in the underlying
OrderedDictwith keys likePROP:n, wherePROPis the uppercase property name andnis a 1-indexed count of how many duplicates have appeared so far. These keys are purely an implementation detail; aforementioned:nsuffix is removed during serialization.Key casing is now preserved during serialization. Note that keys are still coerced to uppercase for the
OrderedDictinterface. For example, if a simfile’s title is declared using#Title:MAX 300;, the title will be accessible viatitleandsim["TITLE"], but it will serialize back to disk with the same case seen during parsing.Ephemeral details such as whitespace & comments are now preserved more intelligently than before. In particular, any comment above a chart definition is now considered attached to the chart; new simfile-level properties will appear above the comment, instead of below it.
v3.0.0a1
Breaking changes
Warning
simfile 3.0 introduces some breaking changes that you may need to update your code to handle:
Python 3.10 or higher required
simfile’s minimum Python version was raised from 3.6 to 3.10.
Strict parsing is now off by default
Functions in the top-level module,
such as simfile.open(), simfile.load(), and simfile.mutate(),
now default to strict=False.
If you want strict parse errors,
pass strict=True to restore the old behavior.
Features that are now optional
The simfile.assets submodule
now requires installing simfile with the assets extra.
Run one of these commands to add it to your project:
pip install 'simfile[assets]' # or...
poetry add 'simfile[assets]' # or...
rye add simfile --features assets
The filesystem parameter of various functions & methods
now requires installing simfile with the fs extra.
Run one of these commands to add it to your project:
pip install 'simfile[fs]' # or...
poetry add 'simfile[fs]' # or...
rye add simfile --features fs
If you want to use both of these optional features, join them with a comma:
pip install 'simfile[assets,fs]' # or...
poetry add 'simfile[assets,fs]' # or...
rye add simfile --features assets,fs
Which command to use depends on what package manager you’re using for your project.
If you’re unsure, use the pip command.
Some dict operations no longer supported on simfiles & charts
The Simfile and Chart classes (both SM and SSC)
no longer inherit OrderedDict;
instead, they have a private OrderedDict attribute
and forward common dictionary methods & operations to it.
These operations that were previously inherited
by Simfile and Chart
are not forwarded:
The
clear,copy,popitem,reversed,setdefault, andupdatemethods fromdictare no longer supported.The
|and|=operators are no longer supported.
These operations are forwarded and should behave the same as before:
[key]indexing & assignmentlen()and iterationThe
move_to_endmethod fromOrderedDictThe
keys,values,items,get, andpopmethods fromdict
TimingData and displaybpm() parameters changed
TimingData and displaybpm() both now take a single argument,
a Simfile or an AttachedChart
(a chart taken from a Simfile - more on this below).
Previously, they took one or two arguments,
a required Simfile and an optional Chart.
If your code passed both a Simfile and a Chart
to either of these classes/functions,
you can probably fix it by removing the first argument (the simfile).
However, this might fail if your Chart is not an AttachedChart.
In that case, append your chart to the simfile’s charts
to attach it to the simfile.
Then you can read the attached chart back from the simfile’s charts.
group_notes() parameters changed
group_notes()’ optional include_note_types parameter was removed.
Use the built-in filter function on the input note data instead.
It was unclear how this parameter interacted with the other parameters.
The fact that such a simple operation was included as a parameter
suggested that it would do something “smarter” under the hood.
Consequently, it was very easy to make mistakes
like excluding NoteType.TAIL while setting join_heads_to_tails to True.
Other submodules of simfile that used group_notes() under the hood
even made mistakes like these!
Enhancements
Strict or non-strict parsing is now pervasive
Simfiles and charts now know whether they were opened with strict parsing
(or default to False when created in memory).
When a simfile is parsed with strict=False:
Stray text and missing semicolon recovery are both allowed during MSD parsing.
BeatValuesuses a lenient float parser that permits trailing junk data.
Attached charts
All charts under a simfile’s charts attribute
are now instances of AttachedChart,
which is a type union for AttachedSMChart and AttachedSSCChart.
These are subclasses of SMChart and SSCChart
that store a reference to the simfile they came from.
Simfile (de)serialization is now exact
Deserializing and serializing a Simfile is now byte-for-byte symmetric
in most cases.
For example,
if you open a simfile with simfile.mutate()
and don’t make any changes,
the output file should exactly match the input file.
This includes whitespace, comments, duplicate & lowercase keys,
and any other ephemeral details.
Note
Known exceptions: Non-chart keys found after the first chart will be moved before the first chart. This is unlikely to change.
Similarly,
newly created properties on Simfile objects
now use a heuristic to determine their suffix
(the ; and any following whitespace)
based on the initial properties seen in the simfile.
For example,
a newly-added property on a file containing Windows-style newlines
will have its suffix set to ;\r\n to match the rest of the file.
msdparser upgraded
simfile’s dependency on msdparser was bumped to 3.0. This is what made the byte-for-byte symmetry described above possible. It also fixes a few parsing bugs that are described below.
Bugfixes
Note counts match StepMania
The simfile.notes.count module has been replaced
by simfile.notes.counter,
which omits fake notes from counts.
The counter module contains many functions with the same names,
but which take an AttachedChart instead of NoteData.
This fixes a long-standing misparity with StepMania’s counts.
Additionally,
count_hands() now takes active holds and rolls into account.
This fixes hands being undercounted when compared to StepMania.
Missing semicolon recovery matches StepMania
Missing semicolon recovery is a feature of StepMania’s parser
that checks for new lines starting with #
and treats them as new parameters,
even if there was no preceding ;.
This was implemented in the msdparser 2.0 dependency,
but it didn’t quite have parity with StepMania’s parser.
In particular,
the new line wasn’t allowed to have whitespace before the #;
only the two-character sequence \n# could trigger it.
msdparser 3.0 corrects this so that preceding whitespace is allowed.
It also correctly removes all trailing whitespace
(such as the line break)
from the preceding component,
which was another mismatch between msdparser 2.0 and StepMania.
openpack() passes kwargs to open()
It didn’t before. Whoops!
v2.1.1
Bugfixes
Two bugs in simfile 2.1.0’s SSC implementation broke multi-value properties, causing them to be truncated or mangled past the first value. This release fixes these issues:
When opening an SSC file, the DISPLAYBPM and ATTACKS properties of both simfiles and charts no longer stop parsing at the first
:. For DISPLAYBPM, this meant a BPM range of120:240would have been incorrectly parsed as a static BPM of120. ATTACKS were completely broken as they use colon as a separator.The aforementioned properties are now correctly serialized from
SSCChart; previously, they would have been escaped with backslashes. This bug had the same effects described above, but only affected manual assignment of multi-value properties (e.g.chart.displaybpm = "120:240") since the first bug shadowed this bug during deserialization.
v2.1.0
New features
The new
simfile.dirmodule offersSimfileDirectoryandSimfilePackclasses for nagivating simfile filesystem structures.The new
simfile.assetsmodule provides anAssetsclass that can reliably discover paths to simfile assets, even if they’re not specified in the simfile.The top-level
simfilemodule now offersopendir()andopenpack()functions as simplified interfaces to thesimfile.dirAPI.PyFilesystem2 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.
The
DisplayBPMclasses 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 forisinstancechecks. Refer to Getting the displayed BPM for more details.
Bugfixes
The
chartsproperty on simfiles is now writable, meaning the list of charts can be overwritten directly (not just added to / removed from).Backslash escape sequences and multi-value MSD parameters are now handled correctly, both when opening and serializing simfiles. See the Enhancements section below for more details.
sm_to_ssc()no longer produces invalid output when there are negative BPMs or stops in the timing data. (It throwsNotImplementedErroras 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,
Iteratorinput arguments have been replaced withIterableso that you don’t need to wrap them initer(...)to suppress type errors from static analyzers.
Enhancements
The dependency on msdparser has been upgraded to version 2. This corrects parsing of escape sequences and multi-value parameters, meaning that
:and\characters inside a value are handled the same way as in StepMania. Additionally, parsing is now up to 10 times faster than before!
v2.0.1
Bugfix: The dependency on msdparser 1.0.0 was mis-specified in both the Pipfile and setup.py. Publishing msdparser 2.0.0-beta.3 (a breaking release) caused fresh installs to be broken. This patch fixes the version specification in both files.
v2.0.0
Initial stable release of version 2. Refer to Migrating from simfile 1.0 to 2.0 for a general overview of the changes since version 1.