Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Reporters #27

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
9 changes: 8 additions & 1 deletion src/passa/cli/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
def build_project(root):
# This is imported lazily to reduce import overhead. Not evey command
# needs the project instance.
from passa.internals.projects import Project
from passa.projects import Project
return Project(os.path.abspath(root))


def configure_reporter():
# This is imported lazily to reduce import overhead.
from passa.reporters import configure_reporter
configure_reporter("stdout")


class BaseCommand(object):
"""A CLI command.
"""
Expand Down Expand Up @@ -51,4 +57,5 @@ def add_arguments(self):
def main(self, options):
# This __dict__ access is needed for Python 2 to prevent Python from
# wrapping parsed_main into an unbounded method.
configure_reporter()
return type(self).__dict__["parsed_main"](options)
16 changes: 14 additions & 2 deletions src/passa/cli/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,27 @@ def main(options):
if not success:
return

project._l.write()
print("Written to project at", project.root)
if options.dry_run:
print(project._l.dumps())
else:
project._l.write()
print("Written to project at", project.root)


class Command(BaseCommand):

name = "lock"
description = "Generate Pipfile.lock."
parsed_main = main

def add_arguments(self):
super(Command, self).add_arguments()
self.parser.add_argument(
"--dry-run",
action="store_true", default=False,
help="run locking on Pipfile, but do not write to Pipfile.lock",
)


if __name__ == "__main__":
Command.run_current_module()
17 changes: 10 additions & 7 deletions src/passa/internals/lockers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import resolvelib
import vistir

from passa import reporters

from .caches import HashCache
from .hashes import get_hashes
from .metadata import set_metadata
from .providers import BasicProvider, EagerUpgradeProvider, PinReuseProvider
from .reporters import StdOutReporter
from .traces import trace_graph
from .utils import identify_requirment

Expand Down Expand Up @@ -100,10 +101,6 @@ def __repr__(self):
def get_provider(self):
raise NotImplementedError

def get_reporter(self):
# TODO: Build SpinnerReporter, and use this only in verbose mode.
return StdOutReporter(self.requirements)

def lock(self):
"""Lock specified (abstract) requirements into (concrete) candidates.

Expand All @@ -116,14 +113,20 @@ def lock(self):
* Populate markers based on dependency specifications of each
candidate, and the dependency graph.
"""
reporters.report("lock-starting", {"requirements": self.requirements})

provider = self.get_provider()
reporter = self.get_reporter()
resolver = resolvelib.Resolver(provider, reporter)
resolver = resolvelib.Resolver(
provider, reporters.get_reporter().build_for_resolvelib(),
)

with vistir.cd(self.project.root):
state = resolver.resolve(self.requirements)

traces = trace_graph(state.graph)
reporters.report("lock-trace-ended", {
"state": state, "traces": traces,
})

hash_cache = HashCache()
for r in state.mapping.values():
Expand Down
90 changes: 0 additions & 90 deletions src/passa/internals/reporters.py

This file was deleted.

16 changes: 3 additions & 13 deletions src/passa/operations/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,15 @@

from resolvelib import NoVersionsAvailable, ResolutionImpossible

from passa.internals.reporters import print_requirement
from passa import reporters


def lock(locker):
success = False
try:
locker.lock()
except NoVersionsAvailable as e:
print("\nCANNOT RESOLVE. NO CANDIDATES FOUND FOR:")
print("{:>40}".format(e.requirement.as_line(include_hashes=False)))
if e.parent:
line = e.parent.as_line(include_hashes=False)
print("{:>41}".format("(from {})".format(line)))
else:
print("{:>41}".format("(user)"))
except ResolutionImpossible as e:
print("\nCANNOT RESOLVE.\nOFFENDING REQUIREMENTS:")
for r in e.requirements:
print_requirement(r)
except (NoVersionsAvailable, ResolutionImpossible) as e:
reporters.report("lock-failed", {"exception": e})
else:
success = True
return success
File renamed without changes.
31 changes: 31 additions & 0 deletions src/passa/reporters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- coding=utf-8 -*-

from __future__ import absolute_import, print_function, unicode_literals

from .base import BaseReporter


_REPORTER = BaseReporter()


def _get_stdout_reporter():
from .stdout import Reporter
return Reporter()


def configure_reporter(name):
global _REPORTER
_REPORTER = {
None: BaseReporter,
"stdout": _get_stdout_reporter,
}[name]()


def get_reporter():
return _REPORTER


def report(event, context=None):
if context is None:
context = {}
_REPORTER.report(event, context)
52 changes: 52 additions & 0 deletions src/passa/reporters/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding=utf-8 -*-

from __future__ import absolute_import, print_function, unicode_literals

import resolvelib


class ResolveLibReporter(resolvelib.BaseReporter):
"""Implementation of a ResolveLib reporter that bridge messages.
"""
def __init__(self, parent):
super(ResolveLibReporter, self).__init__()
self.parent = parent

def starting(self):
self.parent.report("resolvelib-starting", {"child": self})

def ending_round(self, index, state):
self.parent.report("resolvelib-ending-round", {
"child": self, "index": index, "state": state,
})

def ending(self, state):
self.parent.report("resolvelib-ending", {
"child": self, "state": state,
})


class BaseReporter(object):
"""Basic reporter that does nothing.
"""
def build_for_resolvelib(self):
"""Build a reporter for ResolveLib.
"""
return ResolveLibReporter(self)

def report(self, event, context):
"""Report an event.

The default behavior is to look for a "handle_EVENT" method on the
class to execute, or do nothing if there is no such method.

:param event: A string to indicate the event.
:param context: A mapping containing appropriate data for the handling
function.
"""
handler_name = "handle_{}".format(event.replace("-", "_"))
try:
handler = getattr(self, handler_name)
except AttributeError:
return
handler(context or {})
Loading