Skip to content

Commit

Permalink
refactor: rename allow flags
Browse files Browse the repository at this point in the history
  • Loading branch information
msto committed Apr 11, 2024
1 parent d046cd3 commit 428a003
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 28 deletions.
2 changes: 1 addition & 1 deletion sam_tags/community/cellranger_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from sam_tags import sam_tag


@sam_tag(strict=False, permit_standard_tag_collisions=True)
@sam_tag(allow_unconventional_local_names=True, allow_standard_tag_collisions=True)
class CellrangerTag(StrEnum):
"""
CellRanger-specific optional fields.
Expand Down
49 changes: 26 additions & 23 deletions sam_tags/sam_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,31 @@

def sam_tag(
*args: EnumerationT,
strict: bool = True,
permit_standard_tag_collisions: bool = False,
allow_unconventional_local_names: bool = False,
allow_standard_tag_collisions: bool = False,
) -> type[Enum] | Callable[..., type[Enum]]:
"""
Declare a locally-defined group of SAM tags.
This decorator enforces the following conventions on the decorated enum:
This decorator always enforces the following conventions on the decorated enum:
1. SAM tags must be two-character strings matching the regex
`[A-Za-z][A-Za-z0-9]`, i.e. the first character must be an alphabetical
character and the second must be an alphanumeric character.
1. SAM tags must be two-character strings matching the regex `[A-Za-z][A-Za-z0-9]`, i.e. the
first character must be an alphabetical character and the second must be an alphanumeric
character.
2. SAM tags must be unique.
3. SAM tags must not be a predefined standard tag.
4. The enumeration class must inherit from `StrEnum` or `str`.
3. The enumeration class must inherit from `StrEnum` or `str`.
Additionally, the following conventions are enforced when `strict=True`:
Additionally, the following optional conventions are enforced by default, but may be disabled:
1. Locally-defined tags must adhere to SAM convention, namely that tags
start with "X", "Y", or "Z", or are lowercase.
1. Locally-defined tags must adhere to SAM convention, namely that tags start with "X", "Y", or
"Z", or are lowercase.
2. SAM tags must not be a predefined standard tag.
Args:
permit_standard_tag_collisions: If True, custom SAM tags may be the same as a predefined
allow_unconventional_local_names: If True, custom SAM tags do not have to adhere to SAM
conventions for the locally-defined tag namespace. (i.e. they may be uppercase and start
with a letter besides "X", "Y", or "Z".)
allow_standard_tag_collisions: If True, custom SAM tags may be the same as a predefined
standard tag.
"""

Expand All @@ -54,16 +57,16 @@ def validate_sam_tag_enum(enumeration: EnumerationT) -> type[Enum]:
# Validate that all SAM tags are valid per SAM spec.
_validate_sam_tags(
enumeration,
strict=strict,
permit_standard_tag_collisions=permit_standard_tag_collisions,
allow_unconventional_local_names=allow_unconventional_local_names,
allow_standard_tag_collisions=allow_standard_tag_collisions,
)

return enumeration

# When the decorator is invoked with keyword arguments (or with
# parentheses), there are no positional arguments. e.g.,
# ```
# @sam_tag(strict=True)
# @sam_tag(allow_unconventional_local_names=True)
# class CustomTag(StrEnum):
# ...
# ```
Expand Down Expand Up @@ -141,8 +144,8 @@ def _validate_sam_tags_are_unique(enumeration: EnumerationT) -> None:

def _validate_sam_tags(
enumeration: EnumerationT,
strict: bool = True,
permit_standard_tag_collisions: bool = False,
allow_unconventional_local_names: bool = True,
allow_standard_tag_collisions: bool = False,
) -> None:
"""
Validate that SAM tags meet convention.
Expand All @@ -155,8 +158,8 @@ def _validate_sam_tags(
for tag in enumeration:
err_msg = _validate_sam_tag(
tag,
strict=strict,
permit_standard_tag_collisions=permit_standard_tag_collisions,
allow_unconventional_local_names=allow_unconventional_local_names,
allow_standard_tag_collisions=allow_standard_tag_collisions,
)
if err_msg is not None:
errs.append(err_msg)
Expand All @@ -169,8 +172,8 @@ def _validate_sam_tags(

def _validate_sam_tag(
tag: Enum,
strict: bool = True,
permit_standard_tag_collisions: bool = False,
allow_unconventional_local_names: bool = True,
allow_standard_tag_collisions: bool = False,
) -> str | None:
"""
Validate an individual SAM tag.
Expand All @@ -182,12 +185,12 @@ def _validate_sam_tag(
if TAG_REGEX.match(tag.value) is None:
return f" {tag}: SAM tags must be two-character alphanumeric strings."

if not permit_standard_tag_collisions and tag.value in [
if not allow_standard_tag_collisions and tag.value in [
standard_tag.value for standard_tag in StandardTag
]:
return f" {tag}: Locally-defined SAM tags may not conflict with a predefined standard tag."

if strict and not _is_valid_local_tag(tag.value):
if not allow_unconventional_local_names and not _is_valid_local_tag(tag.value):
return f" {tag}: Locally-defined SAM tags must be lowercase or start with X, Y, or Z."

return None
Expand Down
8 changes: 4 additions & 4 deletions tests/test_sam_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ class BadTag(StrEnum):
assert msg.endswith("AA: Locally-defined SAM tags must be lowercase or start with X, Y, or Z.")


def test_sam_tag_allows_invalid_local_when_not_strict() -> None:
def test_sam_tag_allows_invalid_local() -> None:
"""
Test that we permit tags which don't adhere to SAM conventions for
locally-defined tags when `strict=False`.
Test that we permit tags which don't adhere to SAM conventions for locally-defined tags when
`allow_unconventional_local_names`.
"""

try:

@sam_tag(strict=False)
@sam_tag(allow_unconventional_local_names=True)
class BadTag(StrEnum):
XB = "AA"

Expand Down

0 comments on commit 428a003

Please sign in to comment.