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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ labelme data_annotated/ --labels labels.txt # specify label list with a file

- `--output` specifies the location that annotations will be written to. If the location ends with .json, a single annotation will be written to this file. Only one image can be annotated if a location is specified with .json. If the location does not end with .json, the program will assume it is a directory. Annotations will be stored in this directory with a name that corresponds to the image that the annotation was made on.
- The first time you run labelme, it will create a config file at `~/.labelmerc`. Add only the settings you want to override. For all available options and their defaults, see [`default_config.yaml`](labelme/_config/default_config.yaml). If you would prefer to use a config file from another location, you can specify this file with the `--config` flag.
- Without the `--nosortlabels` flag, the program will list labels in alphabetical order. When the program is run with this flag, it will display labels in the order that they are provided.
- Without the `--no-sort-labels` flag, the program will list labels in alphabetical order. When the program is run with this flag, it will display labels in the order that they are provided.
- Flags are assigned to an entire image. [Example](examples/classification)
- Labels are assigned to a single polygon. [Example](examples/bbox_detection)

Expand Down
4 changes: 2 additions & 2 deletions examples/instance_segmentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
## Annotation

```bash
labelme data_annotated --labels labels.txt --validatelabel exact --config '{shift_auto_shape_color: -2}'
labelme data_annotated --labels labels.txt --labelflags '{.*: [occluded, truncated], person: [male]}'
labelme data_annotated --labels labels.txt --validate-label exact --config '{shift_auto_shape_color: -2}'
labelme data_annotated --labels labels.txt --label-flags '{.*: [occluded, truncated], person: [male]}'
```

![](.readme/annotation.jpg)
Expand Down
2 changes: 1 addition & 1 deletion examples/semantic_segmentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Annotation

```bash
labelme data_annotated --labels labels.txt --validatelabel exact --config '{shift_auto_shape_color: -2}'
labelme data_annotated --labels labels.txt --validate-label exact --config '{shift_auto_shape_color: -2}'
```

![](.readme/annotation.jpg)
Expand Down
64 changes: 30 additions & 34 deletions labelme/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,31 @@ def _handle_exception(
sys.exit(1)


class _DeprecatedAlias(argparse.Action):
"""Store the value, but FutureWarning when a deprecated alias spelling is used.

The canonical option string is the first one registered; any other spelling
argparse matched (including abbreviations) warns and points back to it.
"""

def __call__(
self,
parser: argparse.ArgumentParser,
namespace: argparse.Namespace,
values: object,
option_string: str | None = None,
) -> None:
canonical = self.option_strings[0]
if option_string is not None and option_string != canonical:
warnings.warn(
f"{option_string} is deprecated and will be removed in a future "
f"version. Use {canonical} instead.",
FutureWarning,
stacklevel=1,
)
setattr(namespace, self.dest, self.const if self.nargs == 0 else values)


def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--version", "-V", action="store_true", help="show version")
Expand Down Expand Up @@ -128,13 +153,6 @@ def main() -> None:
default=default_config_file,
)
# config for the gui
parser.add_argument(
"--nodata",
dest="_deprecated_nodata",
action="store_true",
help=argparse.SUPPRESS,
default=argparse.SUPPRESS,
)
parser.add_argument(
"--with-image-data",
dest="with_image_data",
Expand All @@ -149,18 +167,13 @@ def main() -> None:
help="disable auto save",
default=argparse.SUPPRESS,
)
parser.add_argument(
"--autosave",
dest="_deprecated_autosave",
action="store_true",
help=argparse.SUPPRESS,
default=argparse.SUPPRESS,
)
parser.add_argument(
"--no-sort-labels",
"--nosortlabels", # deprecated
dest="sort_labels",
action="store_false",
action=_DeprecatedAlias,
nargs=0,
const=False,
help="stop sorting labels",
default=argparse.SUPPRESS,
)
Expand All @@ -173,6 +186,7 @@ def main() -> None:
"--label-flags",
"--labelflags", # deprecated
dest="label_flags",
action=_DeprecatedAlias,
help=r"yaml string of label specific flags OR file containing json "
r"string of label specific flags (ex. {person-\d+: [male, tall], "
r"dog-\d+: [black, brown, white], .*: [occluded]})", # NOQA
Expand All @@ -187,6 +201,7 @@ def main() -> None:
"--validate-label",
"--validatelabel", # deprecated
dest="validate_label",
action=_DeprecatedAlias,
choices=["exact"],
help="label validation types",
default=argparse.SUPPRESS,
Expand All @@ -205,25 +220,6 @@ def main() -> None:
)
args = parser.parse_args()

if hasattr(args, "_deprecated_nodata"):
warnings.warn(
"--nodata is deprecated and will be removed in a future version. "
"Image data is no longer stored by default. "
"Use --with-image-data to store it.",
FutureWarning,
stacklevel=1,
)
del args._deprecated_nodata

if hasattr(args, "_deprecated_autosave"):
warnings.warn(
"--autosave is deprecated and will be removed in a future version. "
"Auto save is now enabled by default. Use --no-autosave to disable it.",
FutureWarning,
stacklevel=1,
)
del args._deprecated_autosave

if args.version:
print(f"{__appname__} {__version__}")
sys.exit(0)
Expand Down
58 changes: 58 additions & 0 deletions tests/unit/__main___test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import annotations

import sys
import warnings

import pytest

from labelme.__main__ import main


@pytest.mark.parametrize("flag", ["--nodata", "--autosave"])
def test_removed_flag_errors_as_unknown(
flag: str, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(sys, "argv", ["labelme", flag])
with pytest.raises(SystemExit) as exc:
main()
assert exc.value.code == 2


@pytest.mark.parametrize(
("argv", "canonical"),
[
(["--nosortlabels"], "--no-sort-labels"),
(["--nosort"], "--no-sort-labels"), # argparse abbreviation
(["--labelflags", "{}"], "--label-flags"),
(["--validatelabel", "exact"], "--validate-label"),
],
)
def test_deprecated_alias_warns_pointing_to_canonical(
argv: list[str], canonical: str, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(sys, "argv", ["labelme", *argv, "--version"])
with pytest.warns(FutureWarning, match=canonical):
with pytest.raises(SystemExit) as exc:
main()
assert exc.value.code == 0


@pytest.mark.parametrize(
"argv",
[
["--no-sort-labels"],
["--label-flags", "{}"],
["--validate-label", "exact"],
["--with-image-data"],
["--no-auto-save"],
],
)
def test_canonical_flag_does_not_warn(
argv: list[str], monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(sys, "argv", ["labelme", *argv, "--version"])
with warnings.catch_warnings():
warnings.simplefilter("error", FutureWarning)
with pytest.raises(SystemExit) as exc:
main()
assert exc.value.code == 0
Loading