Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/pythonparser
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6f4c35eacf7c
Choose a base ref
...
head repository: m-labs/pythonparser
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5cb107bbe3de
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jul 7, 2016

  1. Fix python default argument idiocy.

    whitequark committed Jul 7, 2016

    Verified

    This commit was signed with the committer’s verified signature.
    bagder Daniel Stenberg
    Copy the full SHA
    03d87cb View commit details
  2. diagnostic.Engine: allow adding contextual notes.

    whitequark committed Jul 7, 2016
    Copy the full SHA
    5cb107b View commit details
Showing with 47 additions and 1 deletion.
  1. +19 −1 pythonparser/diagnostic.py
  2. +28 −0 pythonparser/test/test_diagnostic.py
20 changes: 19 additions & 1 deletion pythonparser/diagnostic.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@

from __future__ import absolute_import, division, print_function, unicode_literals
from functools import reduce
from contextlib import contextmanager
import sys, re

class Diagnostic:
@@ -38,10 +39,15 @@ class Diagnostic:
"""

def __init__(self, level, reason, arguments, location,
highlights=[], notes=[]):
highlights=None, notes=None):
if level not in self.LEVELS:
raise ValueError("level must be one of Diagnostic.LEVELS")

if highlights is None:
highlights = []
if notes is None:
notes = []

if len(set(map(lambda x: x.source_buffer,
[location] + highlights))) > 1:
raise ValueError("location and highlights must refer to the same source buffer")
@@ -145,16 +151,28 @@ class Engine:
"""
def __init__(self, all_errors_are_fatal=False):
self.all_errors_are_fatal = all_errors_are_fatal
self._appended_notes = []

def process(self, diagnostic):
"""
The default implementation of :meth:`process` renders non-fatal
diagnostics to ``sys.stderr``, and raises fatal ones as a :class:`Error`.
"""
diagnostic.notes += self._appended_notes
self.render_diagnostic(diagnostic)
if diagnostic.level == "fatal" or \
(self.all_errors_are_fatal and diagnostic.level == "error"):
raise Error(diagnostic)

@contextmanager
def context(self, note):
"""
A context manager that appends ``note`` to every diagnostic processed by
this engine.
"""
self._appended_notes.append(note)
yield
self._appended_notes.pop()

def render_diagnostic(self, diagnostic):
sys.stderr.write("\n".join(diagnostic.render()) + "\n")
28 changes: 28 additions & 0 deletions pythonparser/test/test_diagnostic.py
Original file line number Diff line number Diff line change
@@ -25,3 +25,31 @@ def test_render(self):
"x + (1 + 'a')",
" ~ ^ ~~~ "],
diag.render())

class DiagnosticEngineTestCase(unittest.TestCase):

def setUp(self):
self.buffer = source.Buffer("x + (1 + 'a')\n")
self.last_diagnostic = None
self.engine = diagnostic.Engine()
def render_diagnostic(diag):
self.last_diagnostic = diag
self.engine.render_diagnostic = render_diagnostic

def test_context(self):
note = diagnostic.Diagnostic(
"note", "broken here", {},
source.Range(self.buffer, 0, 0))

with self.engine.context(note):
diag = diagnostic.Diagnostic(
"error", "{x} doesn't work", {"x": "everything"},
source.Range(self.buffer, 0, 0))
self.engine.process(diag)
self.assertEqual(self.last_diagnostic.notes, [note])

diag = diagnostic.Diagnostic(
"error", "{x} doesn't work", {"x": "everything"},
source.Range(self.buffer, 0, 0))
self.engine.process(diag)
self.assertEqual(self.last_diagnostic.notes, [])