Usage
The main things to know
BinLog
BinLog represents an Avid bin’s history log. It behaves as a list of BinLogEntry objects, and can be
used to read, process and write properly-formatted .log files.
BinLogEntry
BinLogEntry is a dataclass which represents one entry in such a log. Per the .log file spec,
a BinLogEntry has the following fields:
Field |
Purpose |
Default Value |
|---|---|---|
Timestamp of the modification |
||
Name of the machine that made the modification |
||
Avid user profile name that made the modification |
See About Avid bin logs for more information about Avid bin logs.
Creating new bin logs
Although it’s more likely you’ll be working with existing logs, let’s start by making one from scratch, just to get some concepts down.
1from binhistory import BinLog, BinLogEntry
2
3my_kewl_log = BinLog()
4
5# Add a BinLogEntry with default values
6my_kewl_log.append(BinLogEntry())
7
8# Add a BinLogEntry with specified `computer` and `user` values
9my_kewl_log.append(BinLogEntry(computer="zAutomation", user="otto"))
10
11# Let's see those entries
12for entry in my_kewl_log:
13 print(entry)
Here’s the example output:
BinLogEntry(timestamp=datetime.datetime(2025, 3, 9, 16, 5, 59, 112426), computer='zMichael', user='mjordan')
BinLogEntry(timestamp=datetime.datetime(2025, 3, 9, 16, 5, 59, 112437), computer='zAutomation', user='otto')
The first entry uses default values for timestamp, computer,
and user. The second entry still uses the default timestamp, but
has our custom computer and user values.
Now let’s see how BinLog would format this for the .log file, with BinLog.to_string():
14print(my_kewl_log.to_string())
Output:
Sun Mar 09 16:05:59 Computer: zMichael User: mjordan
Sun Mar 09 16:05:59 Computer: zAutomation User: otto
Great! So let’s write this out as a .log for our Reel 1.avb Avid bin with BinLog.to_bin()
15my_kewl_log.to_bin("01_Edits/Reel 1.avb")
Caution
BinLog.to_bin() will overwrite an existing .log
Reading existing logs
BinLog can read an Avid bin’s log with BinLog.from_bin():
- classmethod BinLog.from_bin(bin_path: str, missing_bin_ok: bool = True, max_year: int | None = None) BinLog
Load an existing .log file for a given bin
If no .log file exists for the given bin, exceptions.BinLogNotFoundError is raised.
So to read the log for the Avid bin 01_Edits/Reel 1.avb:
1from binhistory import BinLog
2from binhistory.exceptions import BinLogNotFoundError
3
4bin_path = "01_EDITS/Reel 1.avb"
5try:
6 log = BinLog.from_bin(bin_path)
7except BinLogNotFoundError:
8 print(f"No log file exist for {bin_path}")
9 return
10
11for entry in log:
12 print(entry)
Here’s an example output from an Avid bin that has been modified four times:
BinLogEntry(timestamp=datetime.datetime(2024, 8, 29, 17, 27, 12), computer='zJoy', user='joyjoy')
BinLogEntry(timestamp=datetime.datetime(2024, 8, 30, 14, 10, 16), computer='zMichael', user='mjordan')
BinLogEntry(timestamp=datetime.datetime(2024, 8, 30, 14, 16, 42), computer='zMichael', user='mjordan')
BinLogEntry(timestamp=datetime.datetime(2025, 2, 22, 18, 5, 43), computer='zTimmy', user='user')
Working with logs
As a list
Since BinLog is a python collections.UserList of BinLogEntry objects, you can do all the usual list-y kinds of things.
1from binhistory import BinLog, BinLogEntry
2from binhistory.exceptions import BinLogTypeError
3
4# Create a log with 5 entries
5my_log = BinLog([BinLogEntry(), BinLogEntry(), BinLogEntry(), BinLogEntry(), BinLogEntry()])
6
7# Get the third entry
8some_entry = my_log[2]
9
10# Modify the third entry
11my_log[2] = some_entry.copy_with(computer="zSomething")
12
13# Add a couple more entries
14my_log.extend([BinLogEntry(computer="zNew"), BinLogEntry(user="Another")])
15
16# Count the entries
17print(f"my_log has {len(my_log)} entries.")
18
19# Note: `BinLog` will only accept `BinLogEntry`s
20try:
21 my_log.append("Heehee oops")
22except BinLogTypeError as e:
23 print(f"This didn't work: {e}")
Convenience methods
Often you may be interested in only the earliest or the last entry in the log. Well, buddy, you’re not gonna believe this:
- BinLog.earliest_entry() BinLogEntry | None
Get the first/earliest entry from a bin log
- BinLog.latest_entry() BinLogEntry | None
Get the last/latest/most recent entry from a bin log
These methods will return None if the BinLog has no BinLogEntrys.
1from binhistory import BinLog
2from binhistory.exceptions import BinLogNotFoundError
3
4bin_path = "01_EDITS/Reel 1.avb"
5try:
6 latest_entry = BinLog.from_bin(bin_path).latest_entry()
7except BinLogNotFoundError:
8 print(f"No log file exist for {bin_path}")
9 return
10
11if not latest_entry:
12 # Sometimes a .log file exists, but is empty
13 print(f"Empty log for {bin_path}")
14 return
15
16print(f"{bin_path} was last modified by {latest_entry.computer} on {latest_entry.timestamp}")
Example output:
01_EDITS/Reel 1.avb was last modified by zTimmy on 2025-02-22 18:05:43
You can also get lists of unique field values in a log with the following:
As an example, let’s get a list of all the bins that have been recently modified by
my zMichael machine. Now we can blame me for things!
1import pathlib
2from binhistory import BinLog
3from binhistory.exceptions import BinLogNotFoundError
4
5suspect = "zMichael"
6
7# Get all the Avid bins in a project
8for bin_path in pathlib.Path("/Volumes/Important Avid Project/").rglob("*.avb"):
9
10 if bin_path.name.startswith("."):
11 # Skip dotfiles
12 continue
13
14 try:
15 # Read the log for this bin
16 log = BinLog.from_bin(bin_path)
17 except BinLogNotFoundError:
18 # Skip bins without logs
19 continue
20
21 if suspect in log.computers():
22 print(f"{suspect} made changes to {bin_path}!")
Working with log entries
As mentioned earlier, a BinLogEntry object is a dataclass that represents a single log entry.
It comes with default values set for each of the fields, so let’s check that out first:
1from binlog import BinLogEntry
2
3print(BinLogEntry())
Output:
BinLogEntry(timestamp=datetime.datetime(2025, 3, 8, 15, 27, 25, 76253), computer='zMichael', user='mjordan')
Nice! We see timestamp defaults to the current datetime. computer
defaults to the hostname of my machine, and user defaults to the username executing the script.
Note
Those default values can be changed, on a per-script basis, by modifying the constants defined in the defaults module.
Now, those first two are in line with the data Avid would use for the log entry under normal circumstances. But
for user, typically Avid would use the name of the current Avid user profile. So let’s specify
that field:
1from binlog import BinLogEntry
2
3print(BinLogEntry(user="MJ 2023.12.2"))
Output:
BinLogEntry(timestamp=datetime.datetime(2025, 3, 8, 15, 28, 29, 47132), computer='zMichael', user='MJ 2023.12.2')
Cool. This matches exactly what Avid would normally use for a bin entry.
Writing logs
The BinLog class knows how to write properly-formatted .log files, and provides a couple
of ways of doing so.
Note
While BinLog may contain any number of BinLogEntry objects in any order, the
resulting .log file will always be output with a maximum of defaults.MAX_ENTRIES of the most recent entries,
sorted according to the BinLogEntry.timestamp field.
Touching a bin
BinLog.touch_bin() is a class method which appends an entry to the log of a given Avid bin. It’s designed to be
a quick thing you can call with no arguments, but you may optionally provide a custom BinLogEntry
If no .log exists for the Avid bin, one will be created.
- classmethod BinLog.touch_bin(bin_path: str, entry: BinLogEntry | None = None, missing_bin_ok: bool = True)
Add an entry to a log file for a given bin
In this example, imagine it’s… oh I don’t know… 3:27pm on March 8, 2025.
1from binhistory import BinLog
2
3bin_path = "01_Edits/Reel 1.avb"
4
5# Add a default BinLogEntry to the log
6BinLog.touch_bin(bin_path)
7
8# Now let's see that log
9print(BinLog.from_bin(bin_path).latest_entry())
The latest entry shows my touch:
BinLogEntry(timestamp=datetime.datetime(2025, 3, 8, 15, 27, 25, 76253), computer='zMichael', user='mjordan')