Skip to content

Commit

Permalink
Add support for custom serialization formats
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Mar 29, 2019
1 parent 65cd191 commit 6d58caa
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

## Unreleased

* Added support for custom serialization formats.

## v0.3.0 (2019-03-29)

* Added Mercurial support.
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ compatible with [PEP 440](https://www.python.org/dev/peps/pep-0440).

## Features

* Supports non-setuptools-based projects, so no need for a setup.py.
* Support for non-setuptools-based projects, so no need for a setup.py.
* Version control system support:
* Git
* Mercurial
* Custom output formats.
* A CLI that allows use with non-Python projects.

## Usage

Expand All @@ -25,6 +27,10 @@ $ dunamai from any
# Or use an explicit VCS:
$ dunamai from git --no-metadata
0.2.0.post7.dev0

# Custom formats:
$ dunamai from git --format "v{base}+{post}.{commit}"
v0.2.0+7.g29045e8
```

Or as a library:
Expand Down
29 changes: 28 additions & 1 deletion dunamai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def __lt__(self, other) -> bool:
raise TypeError("Cannot compare Version with type {}".format(other.__class__.__qualname__))
return pkg_resources.parse_version(self.serialize()) < pkg_resources.parse_version(other.serialize())

def serialize(self, with_metadata: bool = None, with_dirty: bool = False) -> str:
def serialize(self, with_metadata: bool = None, with_dirty: bool = False, format: str = None) -> str:
"""
Create a string from the version info.
Expand All @@ -124,7 +124,34 @@ def serialize(self, with_metadata: bool = None, with_dirty: bool = False) -> str
always include metadata, or set it to False to always exclude it.
:param with_dirty: Set this to True to include a dirty flag in the
metadata if applicable. Inert when with_metadata=False.
:param format: Custom output format. You can use substitutions, such as
"v{base}" to get "v0.1.0". However, note that PEP 440 compliance
is not validated with custom formats. Available substitutions:
* {base}
* {epoch}
* {pre_type}
* {pre_number}
* {post}
* {dev}
* {commit}
* {dirty} which expands to either "dirty" or "clean"
"""
if format is not None:
def blank(value):
return value if value is not None else ""

return format.format(
base=self.base,
epoch=blank(self.epoch),
pre_type=blank(self.pre_type),
pre_number=blank(self.pre_number),
post=blank(self.post),
dev=blank(self.dev),
commit=blank(self.commit),
dirty="dirty" if self.dirty else "clean",
)

out = ""

if self.epoch is not None:
Expand Down
19 changes: 16 additions & 3 deletions dunamai/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,24 @@ def parse_args(argv=None) -> argparse.Namespace:
" see Version.from_*() docs for more info"
),
)
from_sp.add_argument(
"--format",
help=(
"Custom output format. Available substitutions:"
" {base}, {epoch}, {pre_type}, {pre_number}, {post}, {dev}, {commit}, {dirty}"
)
)

return parser.parse_args(argv)


def from_vcs(vcs: Vcs, pattern: Optional[str], with_metadata: Optional[bool], with_dirty: bool) -> None:
def from_vcs(
vcs: Vcs,
pattern: Optional[str],
with_metadata: Optional[bool],
with_dirty: bool,
format: Optional[str],
) -> None:
callbacks = {
Vcs.Any: Version.from_any_vcs,
Vcs.Git: Version.from_git,
Expand All @@ -59,10 +72,10 @@ def from_vcs(vcs: Vcs, pattern: Optional[str], with_metadata: Optional[bool], wi
arguments.append(pattern)

version = callbacks[vcs](*arguments)
print(version.serialize(with_metadata, with_dirty))
print(version.serialize(with_metadata, with_dirty, format))


def main() -> None:
args = parse_args()
if args.command == "from":
from_vcs(Vcs(args.vcs), args.pattern, args.metadata, args.dirty)
from_vcs(Vcs(args.vcs), args.pattern, args.metadata, args.dirty, args.format)
9 changes: 9 additions & 0 deletions tests/test_dunamai.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ def test__version__serialize__with_dirty():
assert Version("0.1.0", post=1, dirty=True).serialize(with_dirty=True) == "0.1.0.post1+dirty"


def test__version__serialize__format():
format = "{epoch},{base},{pre_type},{pre_number},{post},{dev},{commit},{dirty}"
assert Version("0.1.0").serialize(format=format) == ",0.1.0,,,,,,clean"
assert Version(
"1", epoch=2, pre=("a", 3), post=4, dev=5, commit="abc", dirty=True,
).serialize(format=format) == "2,1,a,3,4,5,abc,dirty"


def test__version__serialize__error_conditions():
with pytest.raises(ValueError):
Version("x").serialize()
Expand Down Expand Up @@ -296,6 +304,7 @@ def test__version__from_git(tmp_path):
assert from_vcs() == Version("0.1.0", commit="abc", dirty=False)
assert run("dunamai from git") == "0.1.0"
assert run("dunamai from any") == "0.1.0"
assert run('dunamai from any --format "v{base}"') == "v0.1.0"

(vcs / "foo.txt").write_text("bye")
assert from_vcs() == Version("0.1.0", commit="abc", dirty=True)
Expand Down
18 changes: 11 additions & 7 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,30 @@

def test__parse_args__from():
assert parse_args(["from", "any"]) == Namespace(
command="from", vcs="any", pattern=None, dirty=False, metadata=None,
command="from", vcs="any", pattern=None, dirty=False, metadata=None, format=None,
)
assert parse_args(["from", "git"]) == Namespace(
command="from", vcs="git", pattern=None, dirty=False, metadata=None,
command="from", vcs="git", pattern=None, dirty=False, metadata=None, format=None,
)
assert parse_args(["from", "mercurial"]) == Namespace(
command="from", vcs="mercurial", pattern=None, dirty=False, metadata=None,
command="from", vcs="mercurial", pattern=None, dirty=False, metadata=None, format=None,
)

assert parse_args(["from", "any", "--pattern", r"\d+"]) == Namespace(
command="from", vcs="any", pattern=r"\d+", dirty=False, metadata=None,
command="from", vcs="any", pattern=r"\d+", dirty=False, metadata=None, format=None,
)

assert parse_args(["from", "any", "--metadata"]) == Namespace(
command="from", vcs="any", pattern=None, dirty=False, metadata=True,
command="from", vcs="any", pattern=None, dirty=False, metadata=True, format=None,
)
assert parse_args(["from", "any", "--no-metadata"]) == Namespace(
command="from", vcs="any", pattern=None, dirty=False, metadata=False,
command="from", vcs="any", pattern=None, dirty=False, metadata=False, format=None,
)

assert parse_args(["from", "any", "--dirty"]) == Namespace(
command="from", vcs="any", pattern=None, dirty=True, metadata=None,
command="from", vcs="any", pattern=None, dirty=True, metadata=None, format=None,
)

assert parse_args(["from", "any", "--format", "v{base}"]) == Namespace(
command="from", vcs="any", pattern=None, dirty=False, metadata=None, format="v{base}",
)

0 comments on commit 6d58caa

Please sign in to comment.