From 837cafbc65403b43defd1d623a8c8e016d8ac83f Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:20:48 +0800 Subject: [PATCH 1/8] Add __str__() to Graph and Tree For diagnostic purposes, these print with indentation, unlike __repr__(). --- penman/graph.py | 6 ++++++ penman/tree.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/penman/graph.py b/penman/graph.py index 2a0896c..1c88fbb 100644 --- a/penman/graph.py +++ b/penman/graph.py @@ -109,6 +109,12 @@ def __repr__(self): id(self) ) + def __str__(self): + triples = '[{}]'.format(',\n '.join(map(repr, self.triples))) + epidata = '{{{}}}'.format(',\n '.join( + map('{0[0]!r}: {0[1]!r}'.format, self.epidata.items()))) + return 'Graph(\n {},\n epidata={})'.format(triples, epidata) + def __eq__(self, other): if not isinstance(other, Graph): return NotImplemented diff --git a/penman/tree.py b/penman/tree.py index 3593e6c..71e1acc 100644 --- a/penman/tree.py +++ b/penman/tree.py @@ -38,6 +38,9 @@ def __eq__(self, other) -> bool: def __repr__(self) -> str: return 'Tree({!r})'.format(self.node) + def __str__(self) -> str: + return 'Tree(\n {})'.format(_format(self.node, 2)) + def nodes(self): """ Return the nodes in the tree as a flat list. @@ -45,6 +48,23 @@ def nodes(self): return _nodes(self.node) +def _format(node, level): + var, edges = node + next_level = level + 2 + indent = '\n' + ' ' * next_level + edges = [_format_edge(edge, next_level) for edge in edges] + return '({!r}, [{}{}])'.format(var, indent, (',' + indent).join(edges)) + + +def _format_edge(edge, level): + role, target, epidata = edge + if is_atomic(target): + target = repr(target) + else: + target = _format(target, level) + return '({!r}, {}, {!r})'.format(role, target, epidata) + + def _nodes(node): var, edges = node ns = [] if var is None else [node] From b4209773a8d9ecc036b21aeaea807122e68b40c0 Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:27:05 +0800 Subject: [PATCH 2/8] Add a logger, --verbose and --quiet options The logger is named 'penman', so module-level loggers named, e.g., 'penman.layout', will inherit the 'penman' logger's settings. This makes it so using penman.main (e.g., via the CLI) can set options that don't get set when using it as a library. By default, the loggers are set to the ERROR level, then -v, -vv, and -vvv set it to WARNING, INFO, and DEBUG, respectively. The -q/--quiet option turns off all output, including stdout, which is sometimes useful for commands that test things, but may or may not be useful for Penman. This setup may be re-evaluated later. --- CHANGELOG.md | 7 ++++++- penman/codec.py | 15 +++++++++++---- penman/layout.py | 12 ++++++++++-- penman/lexer.py | 18 ++++++++++++++---- penman/main.py | 21 +++++++++++++++++++++ penman/transform.py | 32 ++++++++++++++++++++++---------- 6 files changed, 84 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f64016..d802b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ ## [Unreleased][unreleased] -(no unreleased changes yet) +### Added + +* `-q` / `--quiet` command line option +* `-v` / `--verbose` command line option +* Loggers that print some diagnostic information at the DEBUG and INFO + levels ## [v0.7.1][v0.7.1] diff --git a/penman/codec.py b/penman/codec.py index e5da608..cfed451 100644 --- a/penman/codec.py +++ b/penman/codec.py @@ -6,6 +6,7 @@ from typing import Optional, Union, Type, Iterable, Iterator, List import re +import logging from penman.types import ( Variable, @@ -29,6 +30,9 @@ from penman import layout +logger = logging.getLogger(__name__) + + class PENMANCodec(object): """ An encoder/decoder for PENMAN-serialized graphs. @@ -102,9 +106,7 @@ def iterparse(self, lines: Union[Iterable[str], str]) -> Iterator[Tree]: """ tokens = lex(lines, pattern=PENMAN_RE) while tokens and tokens.peek().type in ('COMMENT', 'LPAREN'): - metadata = self._parse_comments(tokens) - node = self._parse_node(tokens) - yield Tree(node, metadata=metadata) + yield self._parse(tokens) def parse(self, s: str) -> Tree: """ @@ -120,9 +122,14 @@ def parse(self, s: str) -> Tree: Tree(('b', [('/', 'bark', []), ('ARG1', ('d', [('/', 'dog', [])]), [])])) """ tokens = lex(s, pattern=PENMAN_RE) + return self._parse(tokens) + + def _parse(self, tokens: TokenIterator) -> Tree: metadata = self._parse_comments(tokens) node = self._parse_node(tokens) - return Tree(node, metadata=metadata) + tree = Tree(node, metadata=metadata) + logger.debug('Parsed: %s', tree) + return tree def _parse_comments(self, tokens: TokenIterator): """ diff --git a/penman/layout.py b/penman/layout.py index 0dcd6ad..d6648a5 100644 --- a/penman/layout.py +++ b/penman/layout.py @@ -52,6 +52,7 @@ from typing import Union, Mapping import copy +import logging from penman.exceptions import LayoutError from penman.types import Variable @@ -61,6 +62,9 @@ from penman.model import Model +logger = logging.getLogger(__name__) + + _Nodemap = Mapping[Variable, Union[Node, None]] @@ -104,7 +108,9 @@ def interpret(t: Tree, model: Model = None) -> Graph: if model is None: model = Model() top, triples, epidata = _interpret_node(t.node, model) - return Graph(triples, top=top, epidata=epidata, metadata=t.metadata) + g = Graph(triples, top=top, epidata=epidata, metadata=t.metadata) + logger.info('Interpreted: %s', g) + return g def _interpret_node(t: Node, model: Model): @@ -158,7 +164,9 @@ def configure(g: Graph, if len(data) >= data_count: raise LayoutError('possible cycle in configuration') data = skipped + data - return Tree(node, metadata=g.metadata) + tree = Tree(node, metadata=g.metadata) + logger.debug('Configured: %s', tree) + return tree def _configure(g, top, model, strict): diff --git a/penman/lexer.py b/penman/lexer.py index e6572f1..4f07a80 100644 --- a/penman/lexer.py +++ b/penman/lexer.py @@ -11,6 +11,9 @@ from penman.exceptions import DecodeError +logger = logging.getLogger(__name__) + + # These are the regex patterns for parsing. They must not have any # capturing groups. They are used during lexing and will be # checked by name during parsing. @@ -200,17 +203,24 @@ def lex(lines: Union[Iterable[str], str], else: regex = PENMAN_RE - logging.debug('Lexing with pattern:\n{}'.format(regex.pattern)) - tokens = _lex(lines, regex) return TokenIterator(tokens) def _lex(lines: Iterable[str], regex: Pattern[str]) -> Iterator[Token]: for i, line in enumerate(lines, 1): - for m in regex.finditer(line): + logger.debug('Line %d: %r', i, line) + matches = list(regex.finditer(line)) + tokens = [] + for m in matches: if m.lastgroup is None: raise ValueError( 'Lexer pattern generated a match without a named ' 'capturing group:\n{}'.format(regex.pattern)) - yield Token(m.lastgroup, m.group(), i, m.start(), line) + tokens.append(Token(m.lastgroup, m.group(), i, m.start(), line)) + + if logger.isEnabledFor(logging.DEBUG): + for token in tokens: + logger.debug(token) + + yield from tokens diff --git a/penman/main.py b/penman/main.py index 3efbd39..e9fc085 100644 --- a/penman/main.py +++ b/penman/main.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- import sys +import os import argparse import json +import logging from penman.__about__ import __version__ from penman.model import Model @@ -11,6 +13,9 @@ from penman import transform +logging.basicConfig() # just default arguments; level will be set later + + def process(f, model, out, transform_options, format_options): """Read graphs from *f* and write to *out*.""" @@ -53,6 +58,12 @@ def main(): parser.add_argument( '-V', '--version', action='version', version='Penman v{}'.format(__version__)) + parser.add_argument( + '-v', '--verbose', action='count', dest='verbosity', default=0, + help='increase verbosity') + parser.add_argument( + '-q', '--quiet', action='store_true', + help='suppress output on and ') parser.add_argument( 'FILE', nargs='*', help='read graphs from FILEs instead of stdin') @@ -90,6 +101,16 @@ def main(): args = parser.parse_args() + if args.quiet: + args.verbosity = 0 + sys.stdout.close() + sys.stdout = open(os.devnull, 'w') + else: + args.verbosity = min(args.verbosity, 3) + + logger = logging.getLogger('penman') + logger.setLevel(logging.ERROR - (args.verbosity * 10)) + if args.amr: from penman.models.amr import model elif args.model: diff --git a/penman/transform.py b/penman/transform.py index 842dd2c..8a1f833 100644 --- a/penman/transform.py +++ b/penman/transform.py @@ -4,6 +4,7 @@ """ from typing import Union, List, Tuple +import logging from penman.types import BasicTriple from penman.epigraph import (Epidatum, Epidata) @@ -14,6 +15,9 @@ from penman.layout import (Push, POP) +logger = logging.getLogger(__name__) + + def canonicalize_roles(t: Tree, model: Model) -> Tree: """ Normalize roles in *t* so they are canonical according to *model*. @@ -40,7 +44,9 @@ def canonicalize_roles(t: Tree, model: Model) -> Tree: """ if model is None: model = Model() - return Tree(_canonicalize_node(t.node, model), metadata=t.metadata) + tree = Tree(_canonicalize_node(t.node, model), metadata=t.metadata) + logger.info('Canonicalized roles: %s', tree) + return tree def _canonicalize_node(node: Node, model: Model) -> Node: @@ -96,9 +102,11 @@ def reify_edges(g: Graph, model: Model) -> Graph: # the tree; maybe this should be a tree operation? else: new_triples.append(triple) - return Graph(new_triples, - epidata=new_epidata, - metadata=g.metadata) + g = Graph(new_triples, + epidata=new_epidata, + metadata=g.metadata) + logger.info('Reified edges: %s', g) + return g def contract_edges(g: Graph, model: Model) -> None: @@ -151,9 +159,11 @@ def reify_attributes(g: Graph) -> Graph: new_epidata[node_triple] = node_epis + [POP] else: new_triples.append(triple) - return Graph(new_triples, - epidata=new_epidata, - metadata=g.metadata) + g = Graph(new_triples, + epidata=new_epidata, + metadata=g.metadata) + logger.info('Reified attributes: %s', g) + return g def indicate_branches(g: Graph, model: Model) -> Graph: @@ -203,9 +213,11 @@ def indicate_branches(g: Graph, model: Model) -> Graph: assert isinstance(t[2], str) new_triples.append((t[2], model.top_role, t[0])) new_triples.append(t) - return Graph(new_triples, - epidata=g.epidata, - metadata=g.metadata) + g = Graph(new_triples, + epidata=g.epidata, + metadata=g.metadata) + logger.info('Indicated branches: %s', g) + return g _SplitMarkers = Tuple[Union[Epidatum, None], Epidata, Epidata, Epidata] From 3dd09511072e0ec567e659fba6aa93f5d207810c Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:36:04 +0800 Subject: [PATCH 3/8] Remove superflous POP markers w/ duplicate triples Fixes #34 --- CHANGELOG.md | 5 +++++ penman/layout.py | 3 +++ tests/test_layout.py | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d802b2d..f7f82cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ * Loggers that print some diagnostic information at the DEBUG and INFO levels +### Fixed + +* Remove superfluous `POP` layout markers when graphs have duplicated + triples (#34) + ## [v0.7.1][v0.7.1] The [v0.7.0][v070] release was missing a declaration for the new diff --git a/penman/layout.py b/penman/layout.py index d6648a5..b629be0 100644 --- a/penman/layout.py +++ b/penman/layout.py @@ -164,6 +164,9 @@ def configure(g: Graph, if len(data) >= data_count: raise LayoutError('possible cycle in configuration') data = skipped + data + # remove any superfluous POPs + while data and data[-1] is POP: + data.pop() tree = Tree(node, metadata=g.metadata) logger.debug('Configured: %s', tree) return tree diff --git a/tests/test_layout.py b/tests/test_layout.py index a55f0e5..e5cfab0 100644 --- a/tests/test_layout.py +++ b/tests/test_layout.py @@ -74,3 +74,29 @@ def test_configure(amr_model): ]) ) + +def test_issue_34(): + # https://github.com/goodmami/penman/issues/34 + g = codec.decode(''' + # ::snt I think you failed to not not act. + (t / think + :ARG0 (i / i) + :ARG1 (f / fail + :ARG0 (y / you) + :ARG1 (a / act + :polarity - + :polarity -)))''') + print(configure(g)) + assert configure(g) == Tree( + ('t', [ + ('/', 'think', []), + (':ARG0', ('i', [('/', 'i', [])]), []), + (':ARG1', ('f', [ + ('/', 'fail', []), + (':ARG0', ('y', [('/', 'you', [])]), []), + (':ARG1', ('a', [ + ('/', 'act', []), + (':polarity', '-', []), + (':polarity', '-', [])]), + [])]), + [])])) From 44c710ba8f351f2357afbd1508cb9e56cc4557b3 Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:40:39 +0800 Subject: [PATCH 4/8] Model.reify() no longer inverts incoming triple The idea was to indicate the in/out nature of reified edges without creating epigraphical markers, but this turned out to be more trouble than it was worth, and it wasn't even accurate if the original triple is to be otherwise laid out as inverted. Now it just returns "pure" triples and the caller (e.g., `transform.reify_edges()`) manages the epigraphical markers. --- CHANGELOG.md | 12 ++++++++++++ penman/model.py | 2 +- tests/test_model.py | 6 +++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f82cd..7f5cfa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ * Remove superfluous `POP` layout markers when graphs have duplicated triples (#34) +### Changed + +* `Model.reify()` no longer inverts the incoming triple + + ## [v0.7.1][v0.7.1] The [v0.7.0][v070] release was missing a declaration for the new @@ -27,6 +32,7 @@ installs. This release fixes that. "in case", as I think the missing package problem was the real culprit for faulty documentation builds.) + ## [v0.7.0][v0.7.0] This release comprises a major restructuring from previous @@ -196,6 +202,7 @@ modules. * Remove specific float and int parsing in variables/nodetypes for the default parser (the numeric values are still parses as atoms) (#17) + ## [v0.6.1][v0.6.1] ### Added @@ -213,6 +220,7 @@ modules. * Grammar in README now more accurately reflect parsing behavior (and vice versa) + ## [v0.6.0][] ### Fixed @@ -333,6 +341,7 @@ subclassed to customize behavior. parameter for a serialization codec, and any additional `**kwargs` are passed to its constructor. + ## [v0.3.0][] ### Added @@ -357,6 +366,7 @@ subclassed to customize behavior. * `load()`, `loads()`, `dump()`, and `dumps()` can now take a `triples=...` parameter (default: False); if True, read/write as triples + ## [v0.2.0][] ### Changed @@ -369,6 +379,7 @@ subclassed to customize behavior. of triples (e.g. `instance-of(b, bark-01) ^ ARG0(b, d) ^ instance-of(d, dog)`). + ## [v0.1.0][] First release with very basic functionality. @@ -380,6 +391,7 @@ First release with very basic functionality. * `load()`/`loads()` reads Penman files/strings * `dump()`/`dumps()` writes Penman files/strings + [unreleased]: ../../tree/develop [v0.1.0]: ../../releases/tag/v0.1.0 [v0.2.0]: ../../releases/tag/v0.2.0 diff --git a/penman/model.py b/penman/model.py index d959728..13e027f 100644 --- a/penman/model.py +++ b/penman/model.py @@ -218,6 +218,6 @@ def reify(self, var = '_{}'.format(i) i += 1 - return ((source, self.invert_role(source_role), var), + return ((var, source_role, source), (var, CONCEPT_ROLE, concept), (var, target_role, target)) diff --git a/tests/test_model.py b/tests/test_model.py index 7814876..e87a4f3 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -220,17 +220,17 @@ def test_reify(self, mini_amr): with pytest.raises(ModelError): m.reify(('a', ':ARG0', 'b')) assert m.reify(('a', ':accompanier', 'b')) == ( - ('a', ':ARG0-of', '_'), + ('_', ':ARG0', 'a'), ('_', ':instance', 'accompany-01'), ('_', ':ARG1', 'b')) with pytest.raises(ModelError): assert m.reify(('a', ':domain', 'b')) assert m.reify(('a', ':mod', 'b')) == ( - ('a', ':ARG1-of', '_'), + ('_', ':ARG1', 'a'), ('_', ':instance', 'have-mod-91'), ('_', ':ARG2', 'b')) # ensure unique ids if variables is specified assert m.reify(('a', ':mod', 'b'), variables={'a', 'b', '_'}) == ( - ('a', ':ARG1-of', '_2'), + ('_2', ':ARG1', 'a'), ('_2', ':instance', 'have-mod-91'), ('_2', ':ARG2', 'b')) From 997d4addb2d770a9673b33911f9397603ae75854 Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:44:41 +0800 Subject: [PATCH 5/8] Avoid KeyError when reifying bad graphs Fixes #35 --- CHANGELOG.md | 2 ++ penman/transform.py | 6 ++++-- tests/test_transform.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f5cfa7..b9a9d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ * Remove superfluous `POP` layout markers when graphs have duplicated triples (#34) +* Avoid `KeyError` on edge and attribute reification when graphs have + duplicated triples (#35) ### Changed diff --git a/penman/transform.py b/penman/transform.py index 8a1f833..fccd04f 100644 --- a/penman/transform.py +++ b/penman/transform.py @@ -95,7 +95,8 @@ def reify_edges(g: Graph, model: Model) -> Graph: vars.add(var) # manage epigraphical markers new_epidata[in_triple] = [Push(var)] - node_epis, out_epis = _edge_markers(new_epidata.pop(triple)) + old_epis = new_epidata.pop(triple) if triple in new_epidata else [] + node_epis, out_epis = _edge_markers(old_epis) new_epidata[node_triple] = node_epis new_epidata[out_triple] = out_epis # we don't know where to put the final POP without configuring @@ -154,7 +155,8 @@ def reify_attributes(g: Graph) -> Graph: node_triple = (var, CONCEPT_ROLE, target) new_triples.extend((role_triple, node_triple)) # manage epigraphical markers - role_epis, node_epis = _attr_markers(new_epidata.pop(triple)) + old_epis = new_epidata.pop(triple) if triple in new_epidata else [] + role_epis, node_epis = _attr_markers(old_epis) new_epidata[role_triple] = role_epis + [Push(var)] new_epidata[node_triple] = node_epis + [POP] else: diff --git a/tests/test_transform.py b/tests/test_transform.py index 158091f..09a2f8b 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -106,3 +106,32 @@ def indicate_branches(): g = norm(decode('(a / alpha :mod-of (b / beta))')) assert encode(g) == '(a / alpha :TOP b :mod-of (b / beta))' + + +def test_issue_35(): + # https://github.com/goodmami/penman/issues/35 + + # don't re-encode; these (presumably) bad graphs probably won't + # round-trip without changes. Changes may be predictable, but I + # don't want to test and guarantee some particular output + + g = amr_codec.decode('(a / alpha :mod b :mod (b / beta))') + g = reify_edges(g, amr_model) + assert g.triples == [ + ('a', ':instance', 'alpha'), + ('_', ':ARG1', 'a'), + ('_', ':instance', 'have-mod-91'), + ('_', ':ARG2', 'b'), + ('_2', ':ARG1', 'a'), + ('_2', ':instance', 'have-mod-91'), + ('_2', ':ARG2', 'b'), + ('b', ':instance', 'beta')] + + g = amr_codec.decode('(a / alpha :mod 7 :mod 7))') + g = reify_attributes(g) + assert g.triples == [ + ('a', ':instance', 'alpha'), + ('a', ':mod', '_'), + ('_', ':instance', 7), + ('a', ':mod', '_2'), + ('_2', ':instance', 7)] From b088aa4d43151990aa42a75a0cb2b9f653d3ad11 Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:45:55 +0800 Subject: [PATCH 6/8] Fix setup.py to avoid error when using tox The docs/requirements.txt file is not copied into the files that tox uses to test the code, but this file is read by setup.py, which tox uses to install the module. This caused an error. One fix is to include the file in a MANIFEST.in file, but I don't want to (a) include it in installs and (b) have a MANIFEST.in file. This fix avoids the issue by only reading the file if it is found. --- setup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 4e6bc2a..149dd4e 100755 --- a/setup.py +++ b/setup.py @@ -15,8 +15,13 @@ exec(f.read(), about) # thanks: https://snarky.ca/clarifying-pep-518/ -with open(os.path.join(base_dir, 'docs', 'requirements.txt')) as f: - docs_require = f.readlines() +docs_requirements = os.path.join(base_dir, 'docs', 'requirements.txt') +if os.path.isfile(docs_requirements): + with open(docs_requirements) as f: + docs_require = f.readlines() +else: + docs_require = [] + tests_require = [ 'pytest', From f7d1d22764dbad4ed91a54b2c1bdb6e065ed299f Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 12:58:19 +0800 Subject: [PATCH 7/8] Prepare for v0.7.2 release --- CHANGELOG.md | 5 +++++ docs/conf.py | 2 +- penman/__about__.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a9d47..ab32799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased][unreleased] +(No unreleased changes) + +## [v0.7.2][v0.7.2] + ### Added * `-q` / `--quiet` command line option @@ -406,4 +410,5 @@ First release with very basic functionality. [v0.6.2]: ../../releases/tag/v0.6.2 [v0.7.0]: ../../releases/tag/v0.7.0 [v0.7.1]: ../../releases/tag/v0.7.1 +[v0.7.2]: ../../releases/tag/v0.7.2 [README]: README.md diff --git a/docs/conf.py b/docs/conf.py index 45296ec..739b9b4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ # The short X.Y version version = 'v0.7' # The full version, including alpha/beta/rc tags -release = 'v0.7.1' +release = 'v0.7.2' # -- General configuration --------------------------------------------------- diff --git a/penman/__about__.py b/penman/__about__.py index a1ce5bf..955ba17 100644 --- a/penman/__about__.py +++ b/penman/__about__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -__version__ = '0.7.1' +__version__ = '0.7.2' __version_info__ = [ int(x) if x.isdigit() else x for x in __version__.replace('.', ' ').replace('-', ' ').split() From 9e1eda137bc9f94c53831fb6618c9a852c08cbd2 Mon Sep 17 00:00:00 2001 From: Michael Wayne Goodman Date: Mon, 25 Nov 2019 13:08:46 +0800 Subject: [PATCH 8/8] Fix links in CHANGELOG.md --- CHANGELOG.md | 61 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab32799..7c9e024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,9 +16,9 @@ ### Fixed * Remove superfluous `POP` layout markers when graphs have duplicated - triples (#34) + triples ([#34][]) * Avoid `KeyError` on edge and attribute reification when graphs have - duplicated triples (#35) + duplicated triples ([#35][]) ### Changed @@ -27,7 +27,7 @@ ## [v0.7.1][v0.7.1] -The [v0.7.0][v070] release was missing a declaration for the new +The [v0.7.0](#v070) release was missing a declaration for the new `penman.models` sub-package, so it was not available for new installs. This release fixes that. @@ -123,7 +123,7 @@ modules. * `penman.models.amr.normalizations` * `penman.models.amr.reifications` * `penman.models.amr.model` -* `penman.surface` (#19) +* `penman.surface` ([#19][]) * `penman.surface.AlignmentMarker` * `penman.surface.Alignment` * `penman.surface.RoleAlignment` @@ -131,16 +131,16 @@ modules. * `penman.surface.role_alignments()` * `penman.transform` * `penman.transform.canonicalize_roles()` -* `penman.transform.reify_edges()` (#27) +* `penman.transform.reify_edges()` ([#27][]) * `penman.transform.reify_attributes()` * `penman.transform.indicate_branches()` -* `penman.tree` (#16) +* `penman.tree` ([#16][]) * `penman.tree.Tree` * `penman.tree.is_atomic()` ### Removed -* [docopt](https://github.com/docopt/docopt) dependency (#20) +* [docopt](https://github.com/docopt/docopt) dependency ([#20][]) * `penman.EncodeError` * `penman.AMRCodec` * `penman.Triple.inverted` @@ -154,11 +154,11 @@ modules. ### Fixed -* Graphs can no longer be encoded with attributes as the top (#15) +* Graphs can no longer be encoded with attributes as the top ([#15][]) * For AMR, both `:mod` and `:domain` are for non-inverted relations, - although their inverses can be canonicalized to the other (#26) + although their inverses can be canonicalized to the other ([#26][]) * Epigraphical layout markers allow the tree structure to be preserved - without modifying the pure graph's triples (#25) + without modifying the pure graph's triples ([#25][]) ### Changed @@ -173,10 +173,10 @@ modules. parameters * `penman.PENMANCodec.encode()` now takes `indent` and `compact` parameters -* `penman.PENMANCodec.iterdecode()` works on streams (#21) -* `penman.PENMANCodec` now reads comments with metadata (#23) -* `penman.PENMANCodec` no longer accepts non-symbol variables (#13) -* `penman.dump()` now writes iteratively to a stream (#22) +* `penman.PENMANCodec.iterdecode()` works on streams ([#21][]) +* `penman.PENMANCodec` now reads comments with metadata ([#23][]) +* `penman.PENMANCodec` no longer accepts non-symbol variables ([#13][]) +* `penman.dump()` now writes iteratively to a stream ([#22][]) * The following no longer take the `cls` parameter for a codec class, nor `**kwargs` to configure that class, but instead a `model` parameter for the semantic model: @@ -192,21 +192,21 @@ modules. - `penman.dumps()` - `penman.dump()` * `penman.Graph.triples` is now a member variable instead of a method -* `penman.Graph` class is mutable (#32) +* `penman.Graph` class is mutable ([#32][]) * Concepts (node labels) in `penman.Graph` now have a special role known to the `penman.graph` module, which can help avoid some - reentrancy issues (#29) + reentrancy issues ([#29][]) ## [v0.6.2][v0.6.2] ### Fixed -* Value-cast patterns terminated with `$` to invalid casts (#9) -* Raise EncodeError when attempting to encode empty graphs (#14) -* Redefine NODETYPE_RE for AMRCodec (#17) +* Value-cast patterns terminated with `$` to invalid casts ([#9][]) +* Raise EncodeError when attempting to encode empty graphs ([#14][]) +* Redefine NODETYPE_RE for AMRCodec ([#17][]) * Remove specific float and int parsing in variables/nodetypes for the - default parser (the numeric values are still parses as atoms) (#17) + default parser (the numeric values are still parses as atoms) ([#17][]) ## [v0.6.1][v0.6.1] @@ -412,3 +412,24 @@ First release with very basic functionality. [v0.7.1]: ../../releases/tag/v0.7.1 [v0.7.2]: ../../releases/tag/v0.7.2 [README]: README.md + +[#4]: https://github.com/goodmami/penman/issues/4 +[#6]: https://github.com/goodmami/penman/issues/6 +[#9]: https://github.com/goodmami/penman/issues/9 +[#13]: https://github.com/goodmami/penman/issues/13 +[#14]: https://github.com/goodmami/penman/issues/14 +[#15]: https://github.com/goodmami/penman/issues/15 +[#16]: https://github.com/goodmami/penman/issues/16 +[#17]: https://github.com/goodmami/penman/issues/17 +[#19]: https://github.com/goodmami/penman/issues/19 +[#20]: https://github.com/goodmami/penman/issues/20 +[#21]: https://github.com/goodmami/penman/issues/21 +[#22]: https://github.com/goodmami/penman/issues/22 +[#23]: https://github.com/goodmami/penman/issues/23 +[#25]: https://github.com/goodmami/penman/issues/25 +[#26]: https://github.com/goodmami/penman/issues/26 +[#27]: https://github.com/goodmami/penman/issues/27 +[#29]: https://github.com/goodmami/penman/issues/29 +[#32]: https://github.com/goodmami/penman/issues/32 +[#34]: https://github.com/goodmami/penman/issues/34 +[#35]: https://github.com/goodmami/penman/issues/35