Skip to content

Commit

Permalink
Updated tests to fix delay
Browse files Browse the repository at this point in the history
  • Loading branch information
RhetTbull committed Jun 30, 2024
1 parent 97b1daf commit 962c010
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 12 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Once you've installed osxmetadata with pip, to upgrade to the latest version:
OSXMetaData uses setuptools, thus simply run:

git clone https://github.com/RhetTbull/osxmetadata.git
cd osxmetadata
cd osxmetadata
pip install poetry
poetry install

Expand Down Expand Up @@ -137,9 +137,14 @@ True

The class attributes are handled dynamically which, unfortunately, means that IDEs like PyCharm and Visual Studio Code cannot provide tab-completion for them.

> [!NOTE]
> When writing or updating metadata with OSXMetaData, the OS will take some time to update the metadata on disk; in my testing, this can be as short as 100ms or as long as 3s. This means that if you read the metadata immediately after writing it, you may not see the updated metadata. If your use case requires the use of immediate read after write, you may need to implement a delay in your code to allow the OS time to update the metadata on disk. This appears to be an OS limitation and not something that can be controlled by osxmetadata.
```pycon

## Finder Tags

Unlike other attributes, which are mapped to native Python types appropriate for the source Objective C type, Finder tags (`_kMDItemUserTags` or `tags`) have two components: a name (str) and a color ID (unsigned int in range 0 to 7) representing a color tag in the Finder. Reading tags returns a list of `Tag` namedtuples and setting tags requires a list of `Tag` namedtuples.
Unlike other attributes, which are mapped to native Python types appropriate for the source Objective C type, Finder tags (`_kMDItemUserTags` or `tags`) have two components: a name (str) and a color ID (unsigned int in range 0 to 7) representing a color tag in the Finder. Reading tags returns a list of `Tag` namedtuples and setting tags requires a list of `Tag` namedtuples.

```pycon
>>> from osxmetadata import *
Expand All @@ -149,7 +154,7 @@ Unlike other attributes, which are mapped to native Python types appropriate for
[Tag(name='Test', color=0), Tag(name='ToDo', color=6)]
>>> md.get("_kMDItemUserTags")
[Tag(name='Test', color=0), Tag(name='ToDo', color=6)]
>>>
>>>
```

Tag names (but not colors) can also be accessed through the [NSURLTagNamesKey](https://developer.apple.com/documentation/foundation/nsurltagnameskey) resource key and the label color ID is accessible through `NSURLLabelNumberKey`; the localized label color name is accessible through `NSURLLocalizedLabelKey` though these latter two resource keys only return a single color whereas a file may have more than one color tag. For most purposes, I recommend using the `tags` attribute as it is more convenient and provides access to both the name and color ID of the tag.
Expand Down Expand Up @@ -224,7 +229,7 @@ Metadata attributes which return date/times such as `kMDItemDueDate` or `kMDItem
>>> md.kMDItemDueDate
datetime.datetime(2022, 10, 1, 0, 0)
>>> md.kMDItemDownloadedDate = datetime.datetime(2022, 10, 1, tzinfo=datetime.timezone.utc)
>>>
>>>
```

## Extended Attributes
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
SNOOZE_TIME = 0.5 if os.environ.get("GITHUB_ACTION") else 0.1
# Finder comments need more time to be written to disk
FINDER_COMMENT_SNOOZE = 2.0
LONG_SNOOZE = 3.0 # some tests need a longer snooze time


def snooze(seconds: float = SNOOZE_TIME) -> None:
Expand Down
29 changes: 21 additions & 8 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import datetime
import glob
import json
import os
import pathlib

Expand All @@ -13,7 +14,7 @@
from osxmetadata.__main__ import BACKUP_FILENAME, cli
from osxmetadata.backup import load_backup_file

from .conftest import FINDER_COMMENT_SNOOZE, snooze
from .conftest import FINDER_COMMENT_SNOOZE, LONG_SNOOZE, snooze


def parse_cli_output(output):
Expand Down Expand Up @@ -264,8 +265,13 @@ def test_cli_remove(test_file):
md = OSXMetaData(test_file.name)
md.authors = ["John Doe", "Jane Doe"]
md.tags = [Tag("test", 0)]
snooze()

runner = CliRunner()
result = runner.invoke(cli, ["--list", "--json", test_file.name])
data = json.loads(result.output)
assert sorted(data["kMDItemAuthors"]) == ["Jane Doe", "John Doe"]

result = runner.invoke(
cli,
[
Expand All @@ -275,15 +281,20 @@ def test_cli_remove(test_file):
"--remove",
"tags",
"test,0",
"--verbose",
test_file.name,
],
)
snooze()
assert result.exit_code == 0
assert "Removing John Doe from authors" in result.output
# for some reason this test fails without an additional delay
# for the removed metadata to be updated on disk
# without the additional delay, reading the metadata reads the previous value
snooze(LONG_SNOOZE)

md = OSXMetaData(test_file.name)
assert md.authors == ["Jane Doe"]
assert not md.tags
result = runner.invoke(cli, ["--list", "--json", test_file.name])
data = json.loads(result.output)
assert data["kMDItemAuthors"] == ["Jane Doe"]


def test_cli_mirror(test_file):
Expand Down Expand Up @@ -495,14 +506,15 @@ def test_cli_backup_restore(test_dir):

# wipe the data
result = runner.invoke(cli, ["--wipe", test_file.as_posix()])
snooze()
snooze(LONG_SNOOZE)
md = OSXMetaData(test_file)
assert not md.tags
assert not md.authors
assert not md.stationerypad

# restore the data
result = runner.invoke(cli, ["--restore", test_file.as_posix()])
snooze(LONG_SNOOZE)
assert result.exit_code == 0
assert md.tags == [Tag("test", 0)]
assert md.authors == ["John Doe", "Jane Doe"]
Expand Down Expand Up @@ -556,6 +568,7 @@ def test_cli_order(test_dir):
md.wherefroms = ["http://www.apple.com"]
md.downloadeddate = [datetime.datetime(2019, 1, 1, 0, 0, 0)]
md.findercomment = "Hello World"
snooze(LONG_SNOOZE)

runner = CliRunner()

Expand All @@ -564,7 +577,7 @@ def test_cli_order(test_dir):

# wipe the data
runner.invoke(cli, ["--wipe", test_file.as_posix()])
snooze()
snooze(LONG_SNOOZE)

# restore the data and check order of operations
result = runner.invoke(
Expand Down Expand Up @@ -602,7 +615,7 @@ def test_cli_order(test_dir):
output = parse_cli_output(result.output)
assert output["comment"] == "Hello World"

snooze()
snooze(LONG_SNOOZE)
md = OSXMetaData(test_file)
assert md.authors == ["John Smith", "Jane Smith"]
assert md.findercomment == "Hello World"
Expand Down
1 change: 1 addition & 0 deletions tests/test_datetime_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test datetime_utils """

import datetime
import os
from datetime import date, timezone
Expand Down
16 changes: 16 additions & 0 deletions tests/test_mditem_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,19 @@ def test_get_set_mditem_attribute_value(test_file):
snooze()
assert md.get_mditem_attribute_value("kMDItemComment") == "foo,bar"
assert md.comment == "foo,bar"


def test_attribute_get_set(test_file):
"""Test direct access get/set attribute values"""

md = OSXMetaData(test_file.name)
assert not md.authors
md.authors = ["foo", "bar"]
snooze()
assert md.authors == ["foo", "bar"]
md.authors = ["bar"]
snooze()
assert md.authors == ["bar"]
md.set("authors", ["foo"])
snooze()
assert md.authors == ["foo"]

0 comments on commit 962c010

Please sign in to comment.