On Fri, 2009-10-30 at 17:35 +0000, Leonard Richardson wrote:
> Leonard Richardson has proposed merging lp:~leonardr/launchpadlib/trusted-workflow-tests-2 into lp:launchpadlib.
>
> Requested reviews:
> LAZR Developers (lazr-developers)
>
>
> This branch creates a TrustedTokenAuthorizationConsoleApp, a console
> application that guides the end-user through the process of
> authorizing a request token. It creates a lot of doctests for the App
> object and a small command-line script that invokes it. The doctests
> use the new UserInput class which simulates a user typing things into
> a console application.
>
> There are a lot of small spacing tweaks in this branch to make the
> application look good when run from the command line. These changes
> don't necessarily show up in the doctests, which are much more lenient
> about whitespace.
Did you consider changing your tests to run without the
NORMALIZE_WHITESPACE option, which is enabled by default for all our
tests? But I guess there's no real benefit in making the test more
fragile just to show that the app looks good when running on the command
line.
>
> In addition to the doctests I manually ran the console application to
> test things that can't be automatically tested such as the use of
> getpass and the opening of a page in the web browser.
> --
> + """Exit the app with the specified error code."""
> + sys.exit(code)
> +
> + def getSingleCharInput(self, prompt, valid):
> + """Retrieve a single-character line from the input stream."""
> + valid = valid.upper()
> + input = None
> + while input is None:
> + input = self.input_method(prompt).upper()
> + if len(input) != 1 or input not in valid:
> + input = None
> + return input
> +
> + def pressEnterToExit(self):
> + """Make the user hit enter, and then exit with an error code."""
> + prompt = '\nPress enter to go back to "%s". ' % self.consumer_name
> + self.input_method(prompt)
> + self.exit_with(self.error_code)
> + return self.error_code
Since exit_with() will call sys.exit(), there's no reason to return
anything here, is there?
On Fri, 2009-10-30 at 17:35 +0000, Leonard Richardson wrote: horizationConso leApp, a console
> Leonard Richardson has proposed merging lp:~leonardr/launchpadlib/trusted-workflow-tests-2 into lp:launchpadlib.
>
> Requested reviews:
> LAZR Developers (lazr-developers)
>
>
> This branch creates a TrustedTokenAut
> application that guides the end-user through the process of
> authorizing a request token. It creates a lot of doctests for the App
> object and a small command-line script that invokes it. The doctests
> use the new UserInput class which simulates a user typing things into
> a console application.
>
> There are a lot of small spacing tweaks in this branch to make the
> application look good when run from the command line. These changes
> don't necessarily show up in the doctests, which are much more lenient
> about whitespace.
Did you consider changing your tests to run without the WHITESPACE option, which is enabled by default for all our
NORMALIZE_
tests? But I guess there's no real benefit in making the test more
fragile just to show that the app looks good when running on the command
line.
>
> In addition to the doctests I manually ran the console application to
> test things that can't be automatically tested such as the use of
> getpass and the opening of a page in the web browser.
> --
> === modified file 'src/launchpadl ib/apps. py' b/apps. py 2009-10-28 17:27:53 +0000 b/apps. py 2009-10-30 17:35:17 +0000 thorizationCons oleApp' , credentials import Credentials credentials import ( horizationEngin e, TokenAuthorizat ionException) dumps(token) horizationConso leApp(RequestTo kenAuthorizatio nEngine) : raw_input) : Credentials. DICT_TOKEN_ FORMAT into get_request_ token, load the dict as JSON, and look levels. split(' ,')] kenAuthorizatio nConsoleApp, self).__init__( ionException, e: ToExit( )
> --- src/launchpadli
> +++ src/launchpadli
> @@ -20,9 +20,18 @@
> themselves are kept in bin/.
> """
>
> +__all__ = [
> + 'RequestTokenApp',
> + 'TrustedTokenAu
> + ]
> +
> +import getpass
> +import sys
> +
> import simplejson
>
> -from launchpadlib.
> +from launchpadlib.
> + Credentials, RequestTokenAut
> from launchpadlib.uris import lookup_web_root
>
>
> @@ -43,3 +52,124 @@
> return simplejson.
>
>
> +class TrustedTokenAut
> + """An application that authorizes request tokens."""
> +
> + def __init__(self, web_root, consumer_name, request_token,
> + access_levels='', input_method=
> + """Constructor.
> +
> + :param access_levels: A string of comma-separated access level
> + values. To get an up-to-date list of access levels, pass
> + token_format=
> + Credentials.
> + in 'access_levels'.
> + """
> + access_levels = [level.strip() for level in access_
> + super(TrustedTo
> + web_root, consumer_name, request_token, access_levels)
> +
> + self.input_method = input_method
> +
> + def run(self):
> + """Try to authorize a request token from user input."""
> + self.error_code = -1 # Start off assuming failure.
> + start = "Launchpad credential client (console)"
> + self.output(start)
> + self.output("-" * len(start))
> +
> + try:
> + self()
> + except TokenAuthorizat
> + print str(e)
> + self.error_code = -1
> + return self.pressEnter
The above call is redundant because of the one below, no?
> + return self.pressEnter ToExit( )
> +
> + def exit_with(self, code):
Why is this not exitWith()?
> + """Exit the app with the specified error code.""" put(self, prompt, valid): method( prompt) .upper( ) t(self) : method( prompt) with(self. error_code)
> + sys.exit(code)
> +
> + def getSingleCharIn
> + """Retrieve a single-character line from the input stream."""
> + valid = valid.upper()
> + input = None
> + while input is None:
> + input = self.input_
> + if len(input) != 1 or input not in valid:
> + input = None
> + return input
> +
> + def pressEnterToExi
> + """Make the user hit enter, and then exit with an error code."""
> + prompt = '\nPress enter to go back to "%s". ' % self.consumer_name
> + self.input_
> + self.exit_
> + return self.error_code
Since exit_with() will call sys.exit(), there's no reason to return
anything here, is there?
> + self, cached_username, suggested_message):
> + def input_username(
inputUsername()?
> + """Collect the Launchpad username from the end-user. method( suggested_ message + extra) self, suggested_message): getpass( suggested_ message + " ") method( suggested_ message) level(self, available_levels, suggested_message, option= None): suggested_ message) harInput( prompt, "YN") option[ 'value' ] ED_ACCESS_ LEVEL except_ unauthorized = [ ED_ACCESS_ LEVEL] except_ unauthorized) ): except_ unauthorized[ i]['title' ])) suggested_ message) harInput( prompt, allowed) ED_ACCESS_ LEVEL except_ unauthorized[ int(allow) -1]['value' ] to_authorize( self, suggested_message): suggested_ message) (self, access_level, suggested_message): suggested_ message)
> +
> + :param cached_username: A username from a previous entry attempt,
> + to be presented as the default.
> + """
> + if cached_username is not None:
> + extra = " [%s] " % cached_username
> + else:
> + extra = "\n(No Launchpad account? Just hit enter.) "
> + username = self.input_
> + if username == '':
> + return cached_username
> + return username
> +
> + def input_password(
> + """Collect the Launchpad password from the end-user."""
> + if self.input_method is raw_input:
> + password = getpass.
> + else:
> + password = self.input_
> + return password
> +
> + def input_access_
> + only_one_
> + """Collect the desired level of access from the end-user."""
> + if only_one_option is not None:
> + self.output(
> + prompt = self.message(
> + 'Do you want to give "%(app)s" this level of access? [YN] ')
> + allow = self.getSingleC
> + if allow == "Y":
> + return only_one_
> + else:
> + return self.UNAUTHORIZ
> + else:
> + levels_
> + level for level in available_levels
> + if level['value'] != self.UNAUTHORIZ
> + options = []
> + for i in range(0, len(levels_
> + options.append(
> + "%d: %s" % (i+1, levels_
> + self.output(
> + for option in options:
> + self.output(option)
> + allowed = ("".join(map(str, range(1, i+2)))) + "Q"
> + prompt = self.message(
> + 'What should "%(app)s" be allowed to do using your '
> + 'Launchpad account? [1-%(max)d or Q] ',
> + extra_variables = {'max' : i+1})
> + allow = self.getSingleC
> + if allow == "Q":
> + return self.UNAUTHORIZ
> + else:
> + return levels_
> +
> + def user_refused_
> + """The user refused to authorize a request token."""
> + self.output(
> + self.error_code = -2
> +
> + def user_authorized
> + """The user authorized a request token with some access level."""
> + self.output(
> + self.error_code = 0
The four methods above should be renamed as well, I guess.
Now I'll review the other two files that I didn't because they had
conflicts.
--
Guilherme Salgado <email address hidden>