<commit_before># -*- coding: utf-8 -*-
"""
This module defines the class for decorating controller methods so that on
call the methods can be expressed using expose, validate, and other
decorators to effect a rendered page.
"""

from urllib import url2pathname
import inspect
import formencode
import pylons
from pylons.configuration import config
from pylons import request
from pylons.controllers.util import abort

try:
    from repoze.what.predicates import NotAuthorizedError as WhatNotAuthorizedError, not_anonymous
except ImportError:
    class WhatNotAuthorizedError(Exception): pass
    def not_anonymous(): pass

# demand load tw (ToscaWidets) if needed
tw = None

from tg.render import render as tg_render
from tg.decorators import expose
from tg.flash import flash
from tg.jsonify import is_saobject, JsonEncodeError

from util import pylons_formencode_gettext

# @expose(content_type=CUSTOM_CONTENT_TYPE) won't
# override pylons.request.content_type
CUSTOM_CONTENT_TYPE = 'CUSTOM/LEAVE'

class NotAuthorizedError(Exception): pass

class DecoratedController(object):
    """Creates an interface to hang decoration attributes on
    controller methods for the purpose of rendering web content.
    """

    def _is_exposed(self, controller, name):
        if hasattr(controller, name):
            method = getattr(controller, name)
            if inspect.ismethod(method) and hasattr(method, 'decoration'):
                return method.decoration.exposed

    def _call(self, controller, params, remainder=None):
        """
        _call is called by _perform_call in Pylons' WSGIController.

        Any of the before_validate hook, the validation, the before_call hook,
        and the controller method can return a FormEncode Invalid exception,
        which will give the validation error handler the opportunity to provide
        a replacement decorated controller method and output that will
        subsequently be rendered.

        This allows for validation to display the original page or an
        abbreviated form with validation errors shown on validation failure.

        The before_render hook provides a place for functions that are called
        before the template is rendered. For example, you could use it to
        add and remove from the dictionary returned by the controller method,
        before it is passed to rendering.

        The after_render hook can act upon and modify the response out of
        rendering.

        """

        self._initialize_validation_context()

        #This is necessary to prevent spurious Content Type header which would
        #cause problems to paste.response.replace_header calls and cause
        #responses wihout content type to get out with a wrong content type
        if not pylons.response.headers.get('Content-Type'):
            pylons.response.headers.pop('Content-Type', None)

        pylons.request.start_response = getattr(self, 'start_response', None)

        remainder = remainder or []
        remainder = [url2pathname(r) for r in remainder]

        tg_decoration = controller.decoration
        try:
            if 'tg_format' in params:
                pylons.request.headers['tg_format'] = params['tg_format']

            tg_decoration.run_hooks('before_validate', remainder, params)

            validate_params = self._get_params_with_argspec(controller, params, remainder)

            for ignore in config.get('ignore_parameters', []):
                if params.get(ignore):
                    del params[ignore]

            # Validate user input
            params = self._perform_validate(controller, validate_params)

            pylons.tmpl_context.form_values = params

            tg_decoration.run_hooks('before_call', remainder, params)
            # call controller method

            params, remainder = self._remove_argspec_params_from_params(controller, params, remainder)

            output = controller(*remainder, **dict(params))

        except formencode.api.Invalid, inv:
            controller, output = self._handle_validation_errors(controller,
                                                                remainder,
                                                                params, inv)
        except Exception, e:
            if config.get('use_toscawidgets2'):
                from tw2.core import ValidationError
                if isinstance(e, ValidationError):
                    controller, output = self._handle_validation_errors(controller,
                                                                remainder,
                                                                params, e)
                else:
                    raise
            else:
                raise

        # Render template
        tg_decoration.run_hooks('before_render', remainder, params,
                                        output)
        response = self._render_response(controller, output)
        tg_decoration.run_hooks('after_render', response)
        return response

    def _perform_validate(self, controller, params):
        """
        Validation is stored on the "validation" attribute of the controller's
        decoration.

        If can be in three forms:

        1) A dictionary, with key being the request parameter name, and value a
           FormEncode validator.

        2) A FormEncode Schema object

        3) Any object with a "validate" method that takes a dictionary of the
           request variables.

        Validation can "clean" or otherwise modify the parameters that were
        passed in, not just raise an exception.  Validation exceptions should
        be FormEncode Invalid objects.
        """

        validation = getattr(controller.decoration, 'validation', None)

        if validation is None:
            return params

        # An object used by FormEncode to get translator function
        state = type('state', (),
                {'_': staticmethod(pylons_formencode_gettext)})

        #Initialize new_params -- if it never gets updated just return params
        new_params = {}

        # The validator may be a dictionary, a FormEncode Schema object, or any
        # object with a "validate" method.
        if isinstance(validation.validators, dict):
            # TG developers can pass in a dict of param names and FormEncode
            # validators.  They are applied one by one and builds up a new set
            # of validated params.

            errors = {}
            for field, validator in validation.validators.iteritems():
                try:
                    new_params[field] = validator.to_python(params.get(field),
                            state)
                # catch individual validation errors into the errors dictionary
                except formencode.api.Invalid, inv:
                    errors[field] = inv

            # Parameters that don't have validators are returned verbatim
            for param, param_value in params.items():
                if not param in new_params:
                    new_params[param] = param_value

            # If there are errors, create a compound validation error based on
            # the errors dictionary, and raise it as an exception
            if errors:
                raise formencode.api.Invalid(
                    formencode.schema.format_compound_error(errors),
                    params, None, error_dict=errors)

        elif isinstance(validation.validators, formencode.Schema):
            # A FormEncode Schema object - to_python converts the incoming
            # parameters to sanitized Python values
            new_params = validation.validators.to_python(params, state)

        elif (hasattr(validation.validators, 'validate')
              and getattr(validation, 'needs_controller', False)):
            # An object with a "validate" method - call it with the parameters
            new_params = validation.validators.validate(controller, params, state)

        elif hasattr(validation.validators, 'validate'):
            # An object with a "validate" method - call it with the parameters
            new_params = validation.validators.validate(params, state)

        # Theoretically this should not happen...
        #if new_params is None:
        #    return params

        return new_params

    def _render_response(self, controller, response):
        """
        Render response takes the dictionary returned by the
        controller calls the appropriate template engine. It uses
        information off of the decoration object to decide which engine
        and template to use, and removes anything in the exclude_names
        list from the returned dictionary.

        The exclude_names functionality allows you to pass variables to
        some template rendering engines, but not others. This behavior
        is particularly useful for rendering engines like JSON or other
        "web service" style engines which don't use and explicit
        template, or use a totally generic template.

        All of these values are populated into the context object by the
        expose decorator.
        """

        req = pylons.request._current_obj()
        resp = pylons.response._current_obj()

        content_type, engine_name, template_name, exclude_names = \
            controller.decoration.lookup_template_engine(req)

        if content_type is not None:
            resp.headers['Content-Type'] = content_type

        # if it's a string return that string and skip all the stuff
        if not isinstance(response, dict):
            if engine_name == 'json' and isinstance(response, list):
                raise JsonEncodeError('You may not expose with json a list return value.  This is because'\
                                      ' it leaves your application open to CSRF attacks')
            return response
        """Return a JSON string representation of a Python object."""

        # Save these objects as locals from the SOP to avoid expensive lookups
        tmpl_context = pylons.tmpl_context._current_obj()
        use_legacy_renderer = pylons.configuration.config.get("use_legacy_renderer", True)

        # what causes this condition?  there are no tests for it.
        # this is caused when someone specifies a content_type, but no template
        # because their controller returns a string.
        if template_name is None:
            return response

        # Prepare the engine, if it's not already been prepared.
        if use_legacy_renderer == engine_name:
            # get the buffet handler
            buffet = pylons.buffet._current_obj()

            if engine_name not in _configured_engines():
                template_options = dict(config).get('buffet.template_options', {})
                buffet.prepare(engine_name, **template_options)
                _configured_engines().add(engine_name)

        # If there is an identity, push it to the Pylons template context
        tmpl_context.identity = req.environ.get('repoze.who.identity')

        # Set up the ToscaWidgets renderer
        if engine_name in ('genshi','mako') and config['use_toscawidgets']:
            global tw
            if not tw:
                try:
                    import tw
                except ImportError:
                    pass

            tw.framework.default_view = engine_name

        # Setup the template namespace, removing anything that the user
        # has marked to be excluded.
        namespace = dict(tmpl_context=tmpl_context)
        if isinstance(response, dict):
            namespace.update(response)

        for name in exclude_names:
            namespace.pop(name)

        # If we are in a test request put the namespace where it can be
        # accessed directly
        if req.environ.get('paste.testing'):
            testing_variables = req.environ['paste.testing_variables']
            testing_variables['namespace'] = namespace
            testing_variables['template_name'] = template_name
            testing_variables['exclude_names'] = exclude_names
            testing_variables['controller_output'] = response

        # Render the result.
        if use_legacy_renderer == engine_name:
            result = buffet.render(engine_name=engine_name,
                               template_name=template_name,
                               include_pylons_variables=False,
                               namespace=namespace)
        else:
            result = tg_render(template_vars=namespace,
                      template_engine=engine_name,
                      template_name=template_name)

        if isinstance(result, unicode) and not pylons.response.charset:
            resp.charset = 'UTF-8'

        return result

    def _handle_validation_errors(self, controller, remainder, params, exception):
        """
        Sets up pylons.tmpl_context.form_values and pylons.tmpl_context.form_errors
        to assist generating a form with given values and the validation failure
        messages.

        The error handler in decoration.validation.error_handler is called. If
        an error_handler isn't given, the original controller is used as the
        error handler instead.
        """

        pylons.tmpl_context.validation_exception = exception
        pylons.tmpl_context.form_errors = {}

        # Most Invalid objects come back with a list of errors in the format:
        #"fieldname1: error\nfieldname2: error"

        error_list = exception.__str__().split('\n')

        for error in error_list:
            field_value = error.split(':', 1)

            #if the error has no field associated with it,
            #return the error as a global form error
            if len(field_value) == 1:
                pylons.tmpl_context.form_errors['_the_form'] = field_value[0].strip()
                continue

            pylons.tmpl_context.form_errors[field_value[0]] = field_value[1].strip()

        pylons.tmpl_context.form_values = getattr(exception, 'value', {})

        error_handler = controller.decoration.validation.error_handler
        if error_handler is None:
            error_handler = controller
            output = error_handler(*remainder, **dict(params))
        elif hasattr(error_handler, 'im_self') and error_handler.im_self != controller:
            output = error_handler(error_handler.im_self, *remainder, **dict(params))
        else:
            output = error_handler(controller.im_self, *remainder, **dict(params))

        return error_handler, output

    def _initialize_validation_context(self):
        pylons.tmpl_context.form_errors = {}
        pylons.tmpl_context.form_values = {}

    def _check_security(self):
        predicate = getattr(self, 'allow_only', None)
        if predicate is None:
            return True
        try:
            predicate.check_authorization(pylons.request.environ)
        except WhatNotAuthorizedError, e:
            reason = unicode(e)
            if hasattr(self, '_failed_authorization'):
                # Should shortcircuit the rest, but if not we will still
                # deny authorization
                self._failed_authorization(reason)
            if not_anonymous().is_met(request.environ):
                # The user is authenticated but not allowed.
                code = 403
                status = 'error'
            else:
                # The user has not been not authenticated.
                code = 401
                status = 'warning'
            pylons.response.status = code
            flash(reason, status=status)
            abort(code, comment=reason)
        except NotAuthorizedError, e:
            reason = getattr(e, 'msg', 'You are not Authorized to access this Resource')
            code   = getattr(e, 'code', 401)
            status = getattr(e, 'status', 'error')
            pylons.response.status = code
            flash(reason, status=status)
            abort(code, comment=reason)

def _configured_engines():
    """
    Returns a set containing the names of the currently configured template
    engines from the active application's globals
    """
    g = pylons.app_globals._current_obj()
    if not hasattr(g, 'tg_configured_engines'):
        g.tg_configured_engines = set()
    return g.tg_configured_engines

__all__ = [
    "DecoratedController"
    ]
<commit_msg>Make somehow editable the response inside the after_response hook<commit_after># -*- coding: utf-8 -*-
"""
This module defines the class for decorating controller methods so that on
call the methods can be expressed using expose, validate, and other
decorators to effect a rendered page.
"""

from urllib import url2pathname
import inspect
import formencode
import pylons
from pylons.configuration import config
from pylons import request
from pylons.controllers.util import abort

try:
    from repoze.what.predicates import NotAuthorizedError as WhatNotAuthorizedError, not_anonymous
except ImportError:
    class WhatNotAuthorizedError(Exception): pass
    def not_anonymous(): pass

# demand load tw (ToscaWidets) if needed
tw = None

from tg.render import render as tg_render
from tg.decorators import expose
from tg.flash import flash
from tg.jsonify import is_saobject, JsonEncodeError

from util import pylons_formencode_gettext

# @expose(content_type=CUSTOM_CONTENT_TYPE) won't
# override pylons.request.content_type
CUSTOM_CONTENT_TYPE = 'CUSTOM/LEAVE'

class NotAuthorizedError(Exception): pass

class DecoratedController(object):
    """Creates an interface to hang decoration attributes on
    controller methods for the purpose of rendering web content.
    """

    def _is_exposed(self, controller, name):
        if hasattr(controller, name):
            method = getattr(controller, name)
            if inspect.ismethod(method) and hasattr(method, 'decoration'):
                return method.decoration.exposed

    def _call(self, controller, params, remainder=None):
        """
        _call is called by _perform_call in Pylons' WSGIController.

        Any of the before_validate hook, the validation, the before_call hook,
        and the controller method can return a FormEncode Invalid exception,
        which will give the validation error handler the opportunity to provide
        a replacement decorated controller method and output that will
        subsequently be rendered.

        This allows for validation to display the original page or an
        abbreviated form with validation errors shown on validation failure.

        The before_render hook provides a place for functions that are called
        before the template is rendered. For example, you could use it to
        add and remove from the dictionary returned by the controller method,
        before it is passed to rendering.

        The after_render hook can act upon and modify the response out of
        rendering.

        """

        self._initialize_validation_context()

        #This is necessary to prevent spurious Content Type header which would
        #cause problems to paste.response.replace_header calls and cause
        #responses wihout content type to get out with a wrong content type
        if not pylons.response.headers.get('Content-Type'):
            pylons.response.headers.pop('Content-Type', None)

        pylons.request.start_response = getattr(self, 'start_response', None)

        remainder = remainder or []
        remainder = [url2pathname(r) for r in remainder]

        tg_decoration = controller.decoration
        try:
            if 'tg_format' in params:
                pylons.request.headers['tg_format'] = params['tg_format']

            tg_decoration.run_hooks('before_validate', remainder, params)

            validate_params = self._get_params_with_argspec(controller, params, remainder)

            for ignore in config.get('ignore_parameters', []):
                if params.get(ignore):
                    del params[ignore]

            # Validate user input
            params = self._perform_validate(controller, validate_params)

            pylons.tmpl_context.form_values = params

            tg_decoration.run_hooks('before_call', remainder, params)
            # call controller method

            params, remainder = self._remove_argspec_params_from_params(controller, params, remainder)

            output = controller(*remainder, **dict(params))

        except formencode.api.Invalid, inv:
            controller, output = self._handle_validation_errors(controller,
                                                                remainder,
                                                                params, inv)
        except Exception, e:
            if config.get('use_toscawidgets2'):
                from tw2.core import ValidationError
                if isinstance(e, ValidationError):
                    controller, output = self._handle_validation_errors(controller,
                                                                remainder,
                                                                params, e)
                else:
                    raise
            else:
                raise

        # Render template
        tg_decoration.run_hooks('before_render', remainder, params,output)

        response = dict(response=self._render_response(controller, output))

        tg_decoration.run_hooks('after_render', response)

        return response['response']

    def _perform_validate(self, controller, params):
        """
        Validation is stored on the "validation" attribute of the controller's
        decoration.

        If can be in three forms:

        1) A dictionary, with key being the request parameter name, and value a
           FormEncode validator.

        2) A FormEncode Schema object

        3) Any object with a "validate" method that takes a dictionary of the
           request variables.

        Validation can "clean" or otherwise modify the parameters that were
        passed in, not just raise an exception.  Validation exceptions should
        be FormEncode Invalid objects.
        """

        validation = getattr(controller.decoration, 'validation', None)

        if validation is None:
            return params

        # An object used by FormEncode to get translator function
        state = type('state', (),
                {'_': staticmethod(pylons_formencode_gettext)})

        #Initialize new_params -- if it never gets updated just return params
        new_params = {}

        # The validator may be a dictionary, a FormEncode Schema object, or any
        # object with a "validate" method.
        if isinstance(validation.validators, dict):
            # TG developers can pass in a dict of param names and FormEncode
            # validators.  They are applied one by one and builds up a new set
            # of validated params.

            errors = {}
            for field, validator in validation.validators.iteritems():
                try:
                    new_params[field] = validator.to_python(params.get(field),
                            state)
                # catch individual validation errors into the errors dictionary
                except formencode.api.Invalid, inv:
                    errors[field] = inv

            # Parameters that don't have validators are returned verbatim
            for param, param_value in params.items():
                if not param in new_params:
                    new_params[param] = param_value

            # If there are errors, create a compound validation error based on
            # the errors dictionary, and raise it as an exception
            if errors:
                raise formencode.api.Invalid(
                    formencode.schema.format_compound_error(errors),
                    params, None, error_dict=errors)

        elif isinstance(validation.validators, formencode.Schema):
            # A FormEncode Schema object - to_python converts the incoming
            # parameters to sanitized Python values
            new_params = validation.validators.to_python(params, state)

        elif (hasattr(validation.validators, 'validate')
              and getattr(validation, 'needs_controller', False)):
            # An object with a "validate" method - call it with the parameters
            new_params = validation.validators.validate(controller, params, state)

        elif hasattr(validation.validators, 'validate'):
            # An object with a "validate" method - call it with the parameters
            new_params = validation.validators.validate(params, state)

        # Theoretically this should not happen...
        #if new_params is None:
        #    return params

        return new_params

    def _render_response(self, controller, response):
        """
        Render response takes the dictionary returned by the
        controller calls the appropriate template engine. It uses
        information off of the decoration object to decide which engine
        and template to use, and removes anything in the exclude_names
        list from the returned dictionary.

        The exclude_names functionality allows you to pass variables to
        some template rendering engines, but not others. This behavior
        is particularly useful for rendering engines like JSON or other
        "web service" style engines which don't use and explicit
        template, or use a totally generic template.

        All of these values are populated into the context object by the
        expose decorator.
        """

        req = pylons.request._current_obj()
        resp = pylons.response._current_obj()

        content_type, engine_name, template_name, exclude_names = \
            controller.decoration.lookup_template_engine(req)

        if content_type is not None:
            resp.headers['Content-Type'] = content_type

        # if it's a string return that string and skip all the stuff
        if not isinstance(response, dict):
            if engine_name == 'json' and isinstance(response, list):
                raise JsonEncodeError('You may not expose with json a list return value.  This is because'\
                                      ' it leaves your application open to CSRF attacks')
            return response
        """Return a JSON string representation of a Python object."""

        # Save these objects as locals from the SOP to avoid expensive lookups
        tmpl_context = pylons.tmpl_context._current_obj()
        use_legacy_renderer = pylons.configuration.config.get("use_legacy_renderer", True)

        # what causes this condition?  there are no tests for it.
        # this is caused when someone specifies a content_type, but no template
        # because their controller returns a string.
        if template_name is None:
            return response

        # Prepare the engine, if it's not already been prepared.
        if use_legacy_renderer == engine_name:
            # get the buffet handler
            buffet = pylons.buffet._current_obj()

            if engine_name not in _configured_engines():
                template_options = dict(config).get('buffet.template_options', {})
                buffet.prepare(engine_name, **template_options)
                _configured_engines().add(engine_name)

        # If there is an identity, push it to the Pylons template context
        tmpl_context.identity = req.environ.get('repoze.who.identity')

        # Set up the ToscaWidgets renderer
        if engine_name in ('genshi','mako') and config['use_toscawidgets']:
            global tw
            if not tw:
                try:
                    import tw
                except ImportError:
                    pass

            tw.framework.default_view = engine_name

        # Setup the template namespace, removing anything that the user
        # has marked to be excluded.
        namespace = dict(tmpl_context=tmpl_context)
        if isinstance(response, dict):
            namespace.update(response)

        for name in exclude_names:
            namespace.pop(name)

        # If we are in a test request put the namespace where it can be
        # accessed directly
        if req.environ.get('paste.testing'):
            testing_variables = req.environ['paste.testing_variables']
            testing_variables['namespace'] = namespace
            testing_variables['template_name'] = template_name
            testing_variables['exclude_names'] = exclude_names
            testing_variables['controller_output'] = response

        # Render the result.
        if use_legacy_renderer == engine_name:
            result = buffet.render(engine_name=engine_name,
                               template_name=template_name,
                               include_pylons_variables=False,
                               namespace=namespace)
        else:
            result = tg_render(template_vars=namespace,
                      template_engine=engine_name,
                      template_name=template_name)

        if isinstance(result, unicode) and not pylons.response.charset:
            resp.charset = 'UTF-8'

        return result

    def _handle_validation_errors(self, controller, remainder, params, exception):
        """
        Sets up pylons.tmpl_context.form_values and pylons.tmpl_context.form_errors
        to assist generating a form with given values and the validation failure
        messages.

        The error handler in decoration.validation.error_handler is called. If
        an error_handler isn't given, the original controller is used as the
        error handler instead.
        """

        pylons.tmpl_context.validation_exception = exception
        pylons.tmpl_context.form_errors = {}

        # Most Invalid objects come back with a list of errors in the format:
        #"fieldname1: error\nfieldname2: error"

        error_list = exception.__str__().split('\n')

        for error in error_list:
            field_value = error.split(':', 1)

            #if the error has no field associated with it,
            #return the error as a global form error
            if len(field_value) == 1:
                pylons.tmpl_context.form_errors['_the_form'] = field_value[0].strip()
                continue

            pylons.tmpl_context.form_errors[field_value[0]] = field_value[1].strip()

        pylons.tmpl_context.form_values = getattr(exception, 'value', {})

        error_handler = controller.decoration.validation.error_handler
        if error_handler is None:
            error_handler = controller
            output = error_handler(*remainder, **dict(params))
        elif hasattr(error_handler, 'im_self') and error_handler.im_self != controller:
            output = error_handler(error_handler.im_self, *remainder, **dict(params))
        else:
            output = error_handler(controller.im_self, *remainder, **dict(params))

        return error_handler, output

    def _initialize_validation_context(self):
        pylons.tmpl_context.form_errors = {}
        pylons.tmpl_context.form_values = {}

    def _check_security(self):
        predicate = getattr(self, 'allow_only', None)
        if predicate is None:
            return True
        try:
            predicate.check_authorization(pylons.request.environ)
        except WhatNotAuthorizedError, e:
            reason = unicode(e)
            if hasattr(self, '_failed_authorization'):
                # Should shortcircuit the rest, but if not we will still
                # deny authorization
                self._failed_authorization(reason)
            if not_anonymous().is_met(request.environ):
                # The user is authenticated but not allowed.
                code = 403
                status = 'error'
            else:
                # The user has not been not authenticated.
                code = 401
                status = 'warning'
            pylons.response.status = code
            flash(reason, status=status)
            abort(code, comment=reason)
        except NotAuthorizedError, e:
            reason = getattr(e, 'msg', 'You are not Authorized to access this Resource')
            code   = getattr(e, 'code', 401)
            status = getattr(e, 'status', 'error')
            pylons.response.status = code
            flash(reason, status=status)
            abort(code, comment=reason)

def _configured_engines():
    """
    Returns a set containing the names of the currently configured template
    engines from the active application's globals
    """
    g = pylons.app_globals._current_obj()
    if not hasattr(g, 'tg_configured_engines'):
        g.tg_configured_engines = set()
    return g.tg_configured_engines

__all__ = [
    "DecoratedController"
    ]
<|endoftext|>


<commit_before>#
# Test suite to check compliance with PEP 247, the standard API for
# hashing algorithms.
#

import warnings
warnings.filterwarnings("ignore", "the md5 module is deprecated.*",
                        DeprecationWarning)
warnings.filterwarnings("ignore", "the sha module is deprecated.*",
                        DeprecationWarning)

import md5, sha, hmac

def check_hash_module(module, key=None):
    assert hasattr(module, 'digest_size'), "Must have digest_size"
    assert (module.digest_size is None or
            module.digest_size > 0), "digest_size must be None or positive"

    if key is not None:
        obj1 = module.new(key)
        obj2 = module.new(key, "string")

        h1 = module.new(key, "string").digest()
        obj3 = module.new(key) ; obj3.update("string") ; h2 = obj3.digest()
        assert h1 == h2, "Hashes must match"

    else:
        obj1 = module.new()
        obj2 = module.new("string")

        h1 = module.new("string").digest()
        obj3 = module.new() ; obj3.update("string") ; h2 = obj3.digest()
        assert h1 == h2, "Hashes must match"

    assert hasattr(obj1, 'digest_size'), "Objects must have digest_size attr"
    if module.digest_size is not None:
        assert obj1.digest_size == module.digest_size, "digest_size must match"
    assert obj1.digest_size == len(h1), "digest_size must match actual size"
    obj1.update("string")
    obj_copy = obj1.copy()
    assert obj1.digest() == obj_copy.digest(), "Copied objects must match"
    assert obj1.hexdigest() == obj_copy.hexdigest(), \
           "Copied objects must match"
    digest, hexdigest = obj1.digest(), obj1.hexdigest()
    hd2 = ""
    for byte in digest:
        hd2 += "%02x" % ord(byte)
    assert hd2 == hexdigest, "hexdigest doesn't appear correct"

    print 'Module', module.__name__, 'seems to comply with PEP 247'

if __name__ == '__main__':
    check_hash_module(md5)
    check_hash_module(sha)
    check_hash_module(hmac, key='abc')
<commit_msg>Add a note in the main test class' docstring that the order of execution of the tests is important.<commit_after>#
# Test suite to check compliance with PEP 247, the standard API for
# hashing algorithms.
#

import warnings
warnings.filterwarnings("ignore", "the md5 module is deprecated.*",
                        DeprecationWarning)
warnings.filterwarnings("ignore", "the sha module is deprecated.*",
                        DeprecationWarning)

import md5, sha, hmac
from test.test_support import verbose

def check_hash_module(module, key=None):
    assert hasattr(module, 'digest_size'), "Must have digest_size"
    assert (module.digest_size is None or
            module.digest_size > 0), "digest_size must be None or positive"

    if key is not None:
        obj1 = module.new(key)
        obj2 = module.new(key, "string")

        h1 = module.new(key, "string").digest()
        obj3 = module.new(key) ; obj3.update("string") ; h2 = obj3.digest()
        assert h1 == h2, "Hashes must match"

    else:
        obj1 = module.new()
        obj2 = module.new("string")

        h1 = module.new("string").digest()
        obj3 = module.new() ; obj3.update("string") ; h2 = obj3.digest()
        assert h1 == h2, "Hashes must match"

    assert hasattr(obj1, 'digest_size'), "Objects must have digest_size attr"
    if module.digest_size is not None:
        assert obj1.digest_size == module.digest_size, "digest_size must match"
    assert obj1.digest_size == len(h1), "digest_size must match actual size"
    obj1.update("string")
    obj_copy = obj1.copy()
    assert obj1.digest() == obj_copy.digest(), "Copied objects must match"
    assert obj1.hexdigest() == obj_copy.hexdigest(), \
           "Copied objects must match"
    digest, hexdigest = obj1.digest(), obj1.hexdigest()
    hd2 = ""
    for byte in digest:
        hd2 += "%02x" % ord(byte)
    assert hd2 == hexdigest, "hexdigest doesn't appear correct"

    if verbose:
        print 'Module', module.__name__, 'seems to comply with PEP 247'

def test_main():
    check_hash_module(md5)
    check_hash_module(sha)
    check_hash_module(hmac, key='abc')

if __name__ == '__main__':
    test_main()
<|endoftext|>


<commit_before>'''
   Test cases for pyclbr.py
   Nick Mathewson
'''
from test.test_support import run_unittest
import unittest, sys
from types import ClassType, FunctionType, MethodType, BuiltinFunctionType
import pyclbr
from unittest import TestCase

StaticMethodType = type(staticmethod(lambda: None))
ClassMethodType = type(classmethod(lambda c: None))

# This next line triggers an error on old versions of pyclbr.

from commands import getstatus

# Here we test the python class browser code.
#
# The main function in this suite, 'testModule', compares the output
# of pyclbr with the introspected members of a module.  Because pyclbr
# is imperfect (as designed), testModule is called with a set of
# members to ignore.

class PyclbrTest(TestCase):

    def assertListEq(self, l1, l2, ignore):
        ''' succeed iff {l1} - {ignore} == {l2} - {ignore} '''
        missing = (set(l1) ^ set(l2)) - set(ignore)
        if missing:
            print >>sys.stderr, "l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore)
            self.fail("%r missing" % missing.pop())

    def assertHasattr(self, obj, attr, ignore):
        ''' succeed iff hasattr(obj,attr) or attr in ignore. '''
        if attr in ignore: return
        if not hasattr(obj, attr): print "???", attr
        self.failUnless(hasattr(obj, attr),
                        'expected hasattr(%r, %r)' % (obj, attr))

    def assertHaskey(self, obj, key, ignore):
        ''' succeed iff obj.has_key(key) or key in ignore. '''
        if key in ignore: return
        if not obj.has_key(key):
            print >>sys.stderr, "***",key
        self.failUnless(obj.has_key(key))

    def assertEqualsOrIgnored(self, a, b, ignore):
        ''' succeed iff a == b or a in ignore or b in ignore '''
        if a not in ignore and b not in ignore:
            self.assertEquals(a, b)

    def checkModule(self, moduleName, module=None, ignore=()):
        ''' succeed iff pyclbr.readmodule_ex(modulename) corresponds
            to the actual module object, module.  Any identifiers in
            ignore are ignored.   If no module is provided, the appropriate
            module is loaded with __import__.'''

        if module == None:
            # Import it.
            # ('<silly>' is to work around an API silliness in __import__)
            module = __import__(moduleName, globals(), {}, ['<silly>'])

        dict = pyclbr.readmodule_ex(moduleName)

        def ismethod(oclass, obj, name):
            classdict = oclass.__dict__
            if isinstance(obj, FunctionType):
                if not isinstance(classdict[name], StaticMethodType):
                    return False
            else:
                if not  isinstance(obj, MethodType):
                    return False
                if obj.im_self is not None:
                    if (not isinstance(classdict[name], ClassMethodType) or
                        obj.im_self is not oclass):
                        return False
                else:
                    if not isinstance(classdict[name], FunctionType):
                        return False

            objname = obj.__name__
            if objname.startswith("__") and not objname.endswith("__"):
                objname = "_%s%s" % (obj.im_class.__name__, objname)
            return objname == name

        # Make sure the toplevel functions and classes are the same.
        for name, value in dict.items():
            if name in ignore:
                continue
            self.assertHasattr(module, name, ignore)
            py_item = getattr(module, name)
            if isinstance(value, pyclbr.Function):
                self.assert_(isinstance(py_item, (FunctionType, BuiltinFunctionType)))
            else:
                self.failUnless(isinstance(py_item, (ClassType, type)))
                real_bases = [base.__name__ for base in py_item.__bases__]
                pyclbr_bases = [ getattr(base, 'name', base)
                                 for base in value.super ]

                try:
                    self.assertListEq(real_bases, pyclbr_bases, ignore)
                except:
                    print >>sys.stderr, "class=%s" % py_item
                    raise

                actualMethods = []
                for m in py_item.__dict__.keys():
                    if ismethod(py_item, getattr(py_item, m), m):
                        actualMethods.append(m)
                foundMethods = []
                for m in value.methods.keys():
                    if m[:2] == '__' and m[-2:] != '__':
                        foundMethods.append('_'+name+m)
                    else:
                        foundMethods.append(m)

                try:
                    self.assertListEq(foundMethods, actualMethods, ignore)
                    self.assertEquals(py_item.__module__, value.module)

                    self.assertEqualsOrIgnored(py_item.__name__, value.name,
                                               ignore)
                    # can't check file or lineno
                except:
                    print >>sys.stderr, "class=%s" % py_item
                    raise

        # Now check for missing stuff.
        def defined_in(item, module):
            if isinstance(item, ClassType):
                return item.__module__ == module.__name__
            if isinstance(item, FunctionType):
                return item.func_globals is module.__dict__
            return False
        for name in dir(module):
            item = getattr(module, name)
            if isinstance(item,  (ClassType, FunctionType)):
                if defined_in(item, module):
                    self.assertHaskey(dict, name, ignore)

    def test_easy(self):
        self.checkModule('pyclbr')
        self.checkModule('doctest')
        self.checkModule('rfc822')
        self.checkModule('difflib')

    def test_decorators(self):
        # XXX: See comment in pyclbr_input.py for a test that would fail
        #      if it were not commented out.
        #
        self.checkModule('test.pyclbr_input')

    def test_others(self):
        cm = self.checkModule

        # These were once about the 10 longest modules
        cm('random', ignore=('Random',))  # from _random import Random as CoreGenerator
        cm('cgi', ignore=('log',))      # set with = in module
        cm('mhlib')
        cm('urllib', ignore=('getproxies_registry',
                             'open_https',
                             'getproxies_internetconfig',)) # not on all platforms
        cm('pickle')
        cm('aifc', ignore=('openfp',))  # set with = in module
        cm('Cookie')
        cm('sre_parse', ignore=('dump',)) # from sre_constants import *
        cm('pdb')
        cm('pydoc')

        # Tests for modules inside packages
        cm('email.Parser')
        cm('test.test_pyclbr')

def test_main():
    run_unittest(PyclbrTest)

if __name__ == "__main__":
    test_main()
<commit_msg>Fix the problems in this test.  Boy this is a painful thing to debug -- it's fundamentally unmaintainable.  Should we throw away pyclbr, or rewrite it using the AST?<commit_after>'''
   Test cases for pyclbr.py
   Nick Mathewson
'''
from test.test_support import run_unittest
import unittest, sys
from types import ClassType, FunctionType, MethodType, BuiltinFunctionType
import pyclbr
from unittest import TestCase

StaticMethodType = type(staticmethod(lambda: None))
ClassMethodType = type(classmethod(lambda c: None))

# This next line triggers an error on old versions of pyclbr.

from commands import getstatus

# Here we test the python class browser code.
#
# The main function in this suite, 'testModule', compares the output
# of pyclbr with the introspected members of a module.  Because pyclbr
# is imperfect (as designed), testModule is called with a set of
# members to ignore.

class PyclbrTest(TestCase):

    def assertListEq(self, l1, l2, ignore):
        ''' succeed iff {l1} - {ignore} == {l2} - {ignore} '''
        missing = (set(l1) ^ set(l2)) - set(ignore)
        if missing:
            print >>sys.stderr, "l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore)
            self.fail("%r missing" % missing.pop())

    def assertHasattr(self, obj, attr, ignore):
        ''' succeed iff hasattr(obj,attr) or attr in ignore. '''
        if attr in ignore: return
        if not hasattr(obj, attr): print "???", attr
        self.failUnless(hasattr(obj, attr),
                        'expected hasattr(%r, %r)' % (obj, attr))

    def assertHaskey(self, obj, key, ignore):
        ''' succeed iff obj.has_key(key) or key in ignore. '''
        if key in ignore: return
        if not obj.has_key(key):
            print >>sys.stderr, "***",key
        self.failUnless(obj.has_key(key))

    def assertEqualsOrIgnored(self, a, b, ignore):
        ''' succeed iff a == b or a in ignore or b in ignore '''
        if a not in ignore and b not in ignore:
            self.assertEquals(a, b)

    def checkModule(self, moduleName, module=None, ignore=()):
        ''' succeed iff pyclbr.readmodule_ex(modulename) corresponds
            to the actual module object, module.  Any identifiers in
            ignore are ignored.   If no module is provided, the appropriate
            module is loaded with __import__.'''

        ignore = set(ignore) | set(['object'])

        if module == None:
            # Import it.
            # ('<silly>' is to work around an API silliness in __import__)
            module = __import__(moduleName, globals(), {}, ['<silly>'])

        dict = pyclbr.readmodule_ex(moduleName)

        def ismethod(oclass, obj, name):
            classdict = oclass.__dict__
            if isinstance(obj, FunctionType):
                if not isinstance(classdict[name], StaticMethodType):
                    return False
            else:
                if not  isinstance(obj, MethodType):
                    return False
                if obj.im_self is not None:
                    if (not isinstance(classdict[name], ClassMethodType) or
                        obj.im_self is not oclass):
                        return False
                else:
                    if not isinstance(classdict[name], FunctionType):
                        return False

            objname = obj.__name__
            if objname.startswith("__") and not objname.endswith("__"):
                objname = "_%s%s" % (obj.im_class.__name__, objname)
            return objname == name

        # Make sure the toplevel functions and classes are the same.
        for name, value in dict.items():
            if name in ignore:
                continue
            self.assertHasattr(module, name, ignore)
            py_item = getattr(module, name)
            if isinstance(value, pyclbr.Function):
                self.assert_(isinstance(py_item, (FunctionType, BuiltinFunctionType)))
            else:
                self.failUnless(isinstance(py_item, (ClassType, type)))
                real_bases = [base.__name__ for base in py_item.__bases__]
                pyclbr_bases = [ getattr(base, 'name', base)
                                 for base in value.super ]

                try:
                    self.assertListEq(real_bases, pyclbr_bases, ignore)
                except:
                    print >>sys.stderr, "class=%s" % py_item
                    raise

                actualMethods = []
                for m in py_item.__dict__.keys():
                    if ismethod(py_item, getattr(py_item, m), m):
                        actualMethods.append(m)
                foundMethods = []
                for m in value.methods.keys():
                    if m[:2] == '__' and m[-2:] != '__':
                        foundMethods.append('_'+name+m)
                    else:
                        foundMethods.append(m)

                try:
                    self.assertListEq(foundMethods, actualMethods, ignore)
                    self.assertEquals(py_item.__module__, value.module)

                    self.assertEqualsOrIgnored(py_item.__name__, value.name,
                                               ignore)
                    # can't check file or lineno
                except:
                    print >>sys.stderr, "class=%s" % py_item
                    raise

        # Now check for missing stuff.
        def defined_in(item, module):
            if isinstance(item, ClassType):
                return item.__module__ == module.__name__
            if isinstance(item, FunctionType):
                return item.func_globals is module.__dict__
            return False
        for name in dir(module):
            item = getattr(module, name)
            if isinstance(item,  (ClassType, FunctionType)):
                if defined_in(item, module):
                    self.assertHaskey(dict, name, ignore)

    def test_easy(self):
        self.checkModule('pyclbr')
        self.checkModule('doctest')
        self.checkModule('rfc822')
        self.checkModule('difflib')

    def test_decorators(self):
        # XXX: See comment in pyclbr_input.py for a test that would fail
        #      if it were not commented out.
        #
        self.checkModule('test.pyclbr_input')

    def test_others(self):
        cm = self.checkModule

        # These were once about the 10 longest modules
        cm('random', ignore=('Random',))  # from _random import Random as CoreGenerator
        cm('cgi', ignore=('log',))      # set with = in module
        cm('mhlib')
        cm('urllib', ignore=('getproxies_registry',
                             'open_https',
                             'getproxies_internetconfig',)) # not on all platforms
        cm('pickle')
        cm('aifc', ignore=('openfp',))  # set with = in module
        cm('Cookie', ignore=('Cookie',)) # Cookie is an alias for SmartCookie
        cm('sre_parse', ignore=('dump',)) # from sre_constants import *
        cm('pdb')
        cm('pydoc')

        # Tests for modules inside packages
        cm('email.Parser')
        cm('test.test_pyclbr')

def test_main():
    run_unittest(PyclbrTest)

if __name__ == "__main__":
    test_main()
<|endoftext|>


<commit_before>import test_support
import unittest

from cStringIO import StringIO
from quopri import *

ENCSAMPLE = """\
Here's a bunch of special=20

=A1=A2=A3=A4=A5=A6=A7=A8=A9
=AA=AB=AC=AD=AE=AF=B0=B1=B2=B3
=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE
=BF=C0=C1=C2=C3=C4=C5=C6
=C7=C8=C9=CA=CB=CC=CD=CE=CF
=D0=D1=D2=D3=D4=D5=D6=D7
=D8=D9=DA=DB=DC=DD=DE=DF
=E0=E1=E2=E3=E4=E5=E6=E7
=E8=E9=EA=EB=EC=ED=EE=EF
=F0=F1=F2=F3=F4=F5=F6=F7
=F8=F9=FA=FB=FC=FD=FE=FF

characters... have fun!
"""

# First line ends with a space
DECSAMPLE = "Here's a bunch of special \n" + \
"""\

characters... have fun!
"""

class QuopriTestCase(unittest.TestCase):
    # Each entry is a tuple of (plaintext, encoded string).  These strings are
    # used in the "quotetabs=0" tests.
    STRINGS = (
        # Some normal strings
        ('hello', 'hello'),
        ('''hello
        there
        world''', '''hello
        there
        world'''),
        ('''hello
        there
        world
''', '''hello
        there
        world
'''),
        ('\201\202\203', '=81=82=83'),
        # Add some trailing MUST QUOTE strings
        ('hello ', 'hello=20'),
        ('hello\t', 'hello=09'),
        # Some long lines.  First, a single line of 108 characters
        ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
         '''xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=D8=D9=DA=DB=DC=DD=DE=DFx=
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'''),
        # A line of exactly 76 characters, no soft line break should be needed
        ('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
        'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'),
        # A line of 77 characters, forcing a soft line break at position 75,
        # and a second line of exactly 2 characters (because the soft line
        # break `=' sign counts against the line length limit).
        ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
zz'''),
        # A line of 151 characters, forcing a soft line break at position 75,
        # with a second line of exactly 76 characters and no trailing =
        ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
        # A string containing a hard line break, but which the first line is
        # 151 characters and the second line is exactly 76 characters.  This
        # should leave us with three lines, the first which has a soft line
        # break, and which the second and third do not.
        ('''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz''',
         '''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy=
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
        # Now some really complex stuff ;)
        (DECSAMPLE, ENCSAMPLE),
        )

    # These are used in the "quotetabs=1" tests.
    ESTRINGS = (
        ('hello world', 'hello=20world'),
        ('hello\tworld', 'hello=09world'),
        )

    def test_encodestring(self):
        for p, e in self.STRINGS:
            self.assert_(encodestring(p) == e)

    def test_decodestring(self):
        for p, e in self.STRINGS:
            self.assert_(decodestring(e) == p)

    def test_idempotent_string(self):
        for p, e in self.STRINGS:
            self.assert_(decodestring(encodestring(e)) == e)

    def test_encode(self):
        for p, e in self.STRINGS:
            infp = StringIO(p)
            outfp = StringIO()
            encode(infp, outfp, quotetabs=0)
            self.assert_(outfp.getvalue() == e)

    def test_decode(self):
        for p, e in self.STRINGS:
            infp = StringIO(e)
            outfp = StringIO()
            decode(infp, outfp)
            self.assert_(outfp.getvalue() == p)

    def test_embedded_ws(self):
        for p, e in self.ESTRINGS:
            self.assert_(encodestring(p, quotetabs=1) == e)
            self.assert_(decodestring(e) == p)

test_support.run_unittest(QuopriTestCase)
<commit_msg>Don't use any characters C doesn't guarantee are safe for text-mode files. This should stop the bizarre translations Jack was getting from Mac CVS.<commit_after>import test_support
import unittest

from cStringIO import StringIO
from quopri import *

ENCSAMPLE = """\
Here's a bunch of special=20

=A1=A2=A3=A4=A5=A6=A7=A8=A9
=AA=AB=AC=AD=AE=AF=B0=B1=B2=B3
=B4=B5=B6=B7=B8=B9=BA=BB=BC=BD=BE
=BF=C0=C1=C2=C3=C4=C5=C6
=C7=C8=C9=CA=CB=CC=CD=CE=CF
=D0=D1=D2=D3=D4=D5=D6=D7
=D8=D9=DA=DB=DC=DD=DE=DF
=E0=E1=E2=E3=E4=E5=E6=E7
=E8=E9=EA=EB=EC=ED=EE=EF
=F0=F1=F2=F3=F4=F5=F6=F7
=F8=F9=FA=FB=FC=FD=FE=FF

characters... have fun!
"""

# First line ends with a space
DECSAMPLE = "Here's a bunch of special \n" + \
"""\

\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9
\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3
\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe
\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6
\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf
\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7
\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf
\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7
\xe8\xe9\xea\xeb\xec\xed\xee\xef
\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7
\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff

characters... have fun!
"""

class QuopriTestCase(unittest.TestCase):
    # Each entry is a tuple of (plaintext, encoded string).  These strings are
    # used in the "quotetabs=0" tests.
    STRINGS = (
        # Some normal strings
        ('hello', 'hello'),
        ('''hello
        there
        world''', '''hello
        there
        world'''),
        ('''hello
        there
        world
''', '''hello
        there
        world
'''),
        ('\201\202\203', '=81=82=83'),
        # Add some trailing MUST QUOTE strings
        ('hello ', 'hello=20'),
        ('hello\t', 'hello=09'),
        # Some long lines.  First, a single line of 108 characters
        ('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\xd8\xd9\xda\xdb\xdc\xdd\xde\xdfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
         '''xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=D8=D9=DA=DB=DC=DD=DE=DFx=
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'''),
        # A line of exactly 76 characters, no soft line break should be needed
        ('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
        'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'),
        # A line of 77 characters, forcing a soft line break at position 75,
        # and a second line of exactly 2 characters (because the soft line
        # break `=' sign counts against the line length limit).
        ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
zz'''),
        # A line of 151 characters, forcing a soft line break at position 75,
        # with a second line of exactly 76 characters and no trailing =
        ('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
         '''zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
        # A string containing a hard line break, but which the first line is
        # 151 characters and the second line is exactly 76 characters.  This
        # should leave us with three lines, the first which has a soft line
        # break, and which the second and third do not.
        ('''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz''',
         '''yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy=
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'''),
        # Now some really complex stuff ;)
        (DECSAMPLE, ENCSAMPLE),
        )

    # These are used in the "quotetabs=1" tests.
    ESTRINGS = (
        ('hello world', 'hello=20world'),
        ('hello\tworld', 'hello=09world'),
        )

    def test_encodestring(self):
        for p, e in self.STRINGS:
            self.assert_(encodestring(p) == e)

    def test_decodestring(self):
        for p, e in self.STRINGS:
            self.assert_(decodestring(e) == p)

    def test_idempotent_string(self):
        for p, e in self.STRINGS:
            self.assert_(decodestring(encodestring(e)) == e)

    def test_encode(self):
        for p, e in self.STRINGS:
            infp = StringIO(p)
            outfp = StringIO()
            encode(infp, outfp, quotetabs=0)
            self.assert_(outfp.getvalue() == e)

    def test_decode(self):
        for p, e in self.STRINGS:
            infp = StringIO(e)
            outfp = StringIO()
            decode(infp, outfp)
            self.assert_(outfp.getvalue() == p)

    def test_embedded_ws(self):
        for p, e in self.ESTRINGS:
            self.assert_(encodestring(p, quotetabs=1) == e)
            self.assert_(decodestring(e) == p)

test_support.run_unittest(QuopriTestCase)
<|endoftext|>


<commit_before>import rfc822
import sys
import test_support
import unittest

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

class MessageTestCase(unittest.TestCase):
    def create_message(self, msg):
        return rfc822.Message(StringIO(msg))

    def test_get(self):
        msg = self.create_message(
            'To: "last, first" <userid@foo.net>\n\ntest\n')
        self.assert_(msg.get("to") == '"last, first" <userid@foo.net>')
        self.assert_(msg.get("TO") == '"last, first" <userid@foo.net>')
        self.assert_(msg.get("No-Such-Header") == "")
        self.assert_(msg.get("No-Such-Header", "No-Such-Value")
                     == "No-Such-Value")

    def test_setdefault(self):
        msg = self.create_message(
            'To: "last, first" <userid@foo.net>\n\ntest\n')
        self.assert_(not msg.has_key("New-Header"))
        self.assert_(msg.setdefault("New-Header", "New-Value") == "New-Value")
        self.assert_(msg.setdefault("New-Header", "Different-Value")
                     == "New-Value")
        self.assert_(msg["new-header"] == "New-Value")

        self.assert_(msg.setdefault("Another-Header") == "")
        self.assert_(msg["another-header"] == "")

    def check(self, msg, results):
        """Check addresses and the date."""
        m = self.create_message(msg)
        i = 0
        for n, a in m.getaddrlist('to') + m.getaddrlist('cc'):
            try:
                mn, ma = results[i][0], results[i][1]
            except IndexError:
                print 'extra parsed address:', repr(n), repr(a)
                continue
            i = i + 1
            if mn == n and ma == a:
                pass
            else:
                print 'not found:', repr(n), repr(a)

        out = m.getdate('date')
        if out:
            self.assertEqual(out,
                             (1999, 1, 13, 23, 57, 35, 0, 0, 0),
                             "date conversion failed")

    # Note: all test cases must have the same date (in various formats),
    # or no date!

    def test_basic(self):
        self.check(
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            'From:    Guido van Rossum <guido@CNRI.Reston.VA.US>\n'
            'To:      "Guido van\n'
            '\t : Rossum" <guido@python.org>\n'
            'Subject: test2\n'
            '\n'
            'test2\n',
            [('Guido van\n\t : Rossum', 'guido@python.org')])

        self.check(
            'From: Barry <bwarsaw@python.org\n'
            'To: guido@python.org (Guido: the Barbarian)\n'
            'Subject: nonsense\n'
            'Date: Wednesday, January 13 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('Guido: the Barbarian', 'guido@python.org')])

        self.check(
            'From: Barry <bwarsaw@python.org\n'
            'To: guido@python.org (Guido: the Barbarian)\n'
            'Cc: "Guido: the Madman" <guido@python.org>\n'
            'Date:  13-Jan-1999 23:57:35 EST\n'
            '\n'
            'test',
            [('Guido: the Barbarian', 'guido@python.org'),
             ('Guido: the Madman', 'guido@python.org')
             ])

        self.check(
            'To: "The monster with\n'
            '     the very long name: Guido" <guido@python.org>\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('The monster with\n     the very long name: Guido',
              'guido@python.org')])

        self.check(
            'To: "Amit J. Patel" <amitp@Theory.Stanford.EDU>\n'
            'CC: Mike Fletcher <mfletch@vrtelecom.com>,\n'
            '        "\'string-sig@python.org\'" <string-sig@python.org>\n'
            'Cc: fooz@bat.com, bart@toof.com\n'
            'Cc: goit@lip.com\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('Amit J. Patel', 'amitp@Theory.Stanford.EDU'),
             ('Mike Fletcher', 'mfletch@vrtelecom.com'),
             ("'string-sig@python.org'", 'string-sig@python.org'),
             ('', 'fooz@bat.com'),
             ('', 'bart@toof.com'),
             ('', 'goit@lip.com'),
             ])

    def test_twisted(self):
        # This one is just twisted.  I don't know what the proper
        # result should be, but it shouldn't be to infloop, which is
        # what used to happen!
        self.check(
            'To: <[smtp:dd47@mail.xxx.edu]_at_hmhq@hdq-mdm1-imgout.companay.com>\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('', ''),
             ('', 'dd47@mail.xxx.edu'),
             ('', '_at_hmhq@hdq-mdm1-imgout.companay.com'),
             ])

    def test_commas_in_full_name(self):
        # This exercises the old commas-in-a-full-name bug, which
        # should be doing the right thing in recent versions of the
        # module.
        self.check(
            'To: "last, first" <userid@foo.net>\n'
            '\n'
            'test',
            [('last, first', 'userid@foo.net')])

    def test_quoted_name(self):
        self.check(
            'To: (Comment stuff) "Quoted name"@somewhere.com\n'
            '\n'
            'test',
            [('Comment stuff', '"Quoted name"@somewhere.com')])

    def test_bogus_to_header(self):
        self.check(
            'To: :\n'
            'Cc: goit@lip.com\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('', 'goit@lip.com')])

    def test_addr_ipquad(self):
        self.check(
            'To: guido@[132.151.1.21]\n'
            '\n'
            'foo',
            [('', 'guido@[132.151.1.21]')])

test_support.run_unittest(MessageTestCase)
<commit_msg>test_basic(): Add a test for "person@dom.ain (User J. Person)" which was already correctly parsed (contrary to a comment in Mailman).<commit_after>import rfc822
import sys
import test_support
import unittest

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

class MessageTestCase(unittest.TestCase):
    def create_message(self, msg):
        return rfc822.Message(StringIO(msg))

    def test_get(self):
        msg = self.create_message(
            'To: "last, first" <userid@foo.net>\n\ntest\n')
        self.assert_(msg.get("to") == '"last, first" <userid@foo.net>')
        self.assert_(msg.get("TO") == '"last, first" <userid@foo.net>')
        self.assert_(msg.get("No-Such-Header") == "")
        self.assert_(msg.get("No-Such-Header", "No-Such-Value")
                     == "No-Such-Value")

    def test_setdefault(self):
        msg = self.create_message(
            'To: "last, first" <userid@foo.net>\n\ntest\n')
        self.assert_(not msg.has_key("New-Header"))
        self.assert_(msg.setdefault("New-Header", "New-Value") == "New-Value")
        self.assert_(msg.setdefault("New-Header", "Different-Value")
                     == "New-Value")
        self.assert_(msg["new-header"] == "New-Value")

        self.assert_(msg.setdefault("Another-Header") == "")
        self.assert_(msg["another-header"] == "")

    def check(self, msg, results):
        """Check addresses and the date."""
        m = self.create_message(msg)
        i = 0
        for n, a in m.getaddrlist('to') + m.getaddrlist('cc'):
            try:
                mn, ma = results[i][0], results[i][1]
            except IndexError:
                print 'extra parsed address:', repr(n), repr(a)
                continue
            i = i + 1
            if mn == n and ma == a:
                pass
            else:
                print 'not found:', repr(n), repr(a)

        out = m.getdate('date')
        if out:
            self.assertEqual(out,
                             (1999, 1, 13, 23, 57, 35, 0, 0, 0),
                             "date conversion failed")

    # Note: all test cases must have the same date (in various formats),
    # or no date!

    def test_basic(self):
        self.check(
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            'From:    Guido van Rossum <guido@CNRI.Reston.VA.US>\n'
            'To:      "Guido van\n'
            '\t : Rossum" <guido@python.org>\n'
            'Subject: test2\n'
            '\n'
            'test2\n',
            [('Guido van\n\t : Rossum', 'guido@python.org')])

        self.check(
            'From: Barry <bwarsaw@python.org\n'
            'To: guido@python.org (Guido: the Barbarian)\n'
            'Subject: nonsense\n'
            'Date: Wednesday, January 13 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('Guido: the Barbarian', 'guido@python.org')])

        self.check(
            'From: Barry <bwarsaw@python.org\n'
            'To: guido@python.org (Guido: the Barbarian)\n'
            'Cc: "Guido: the Madman" <guido@python.org>\n'
            'Date:  13-Jan-1999 23:57:35 EST\n'
            '\n'
            'test',
            [('Guido: the Barbarian', 'guido@python.org'),
             ('Guido: the Madman', 'guido@python.org')
             ])

        self.check(
            'To: "The monster with\n'
            '     the very long name: Guido" <guido@python.org>\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('The monster with\n     the very long name: Guido',
              'guido@python.org')])

        self.check(
            'To: "Amit J. Patel" <amitp@Theory.Stanford.EDU>\n'
            'CC: Mike Fletcher <mfletch@vrtelecom.com>,\n'
            '        "\'string-sig@python.org\'" <string-sig@python.org>\n'
            'Cc: fooz@bat.com, bart@toof.com\n'
            'Cc: goit@lip.com\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('Amit J. Patel', 'amitp@Theory.Stanford.EDU'),
             ('Mike Fletcher', 'mfletch@vrtelecom.com'),
             ("'string-sig@python.org'", 'string-sig@python.org'),
             ('', 'fooz@bat.com'),
             ('', 'bart@toof.com'),
             ('', 'goit@lip.com'),
             ])

        self.check(
            'To: person@dom.ain (User J. Person)\n\n',
            [('User J. Person', 'person@dom.ain')])

    def test_twisted(self):
        # This one is just twisted.  I don't know what the proper
        # result should be, but it shouldn't be to infloop, which is
        # what used to happen!
        self.check(
            'To: <[smtp:dd47@mail.xxx.edu]_at_hmhq@hdq-mdm1-imgout.companay.com>\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('', ''),
             ('', 'dd47@mail.xxx.edu'),
             ('', '_at_hmhq@hdq-mdm1-imgout.companay.com'),
             ])

    def test_commas_in_full_name(self):
        # This exercises the old commas-in-a-full-name bug, which
        # should be doing the right thing in recent versions of the
        # module.
        self.check(
            'To: "last, first" <userid@foo.net>\n'
            '\n'
            'test',
            [('last, first', 'userid@foo.net')])

    def test_quoted_name(self):
        self.check(
            'To: (Comment stuff) "Quoted name"@somewhere.com\n'
            '\n'
            'test',
            [('Comment stuff', '"Quoted name"@somewhere.com')])

    def test_bogus_to_header(self):
        self.check(
            'To: :\n'
            'Cc: goit@lip.com\n'
            'Date:    Wed, 13 Jan 1999 23:57:35 -0500\n'
            '\n'
            'test',
            [('', 'goit@lip.com')])

    def test_addr_ipquad(self):
        self.check(
            'To: guido@[132.151.1.21]\n'
            '\n'
            'foo',
            [('', 'guido@[132.151.1.21]')])

    def test_rfc2822_phrases(self):
        # RFC 2822 (the update to RFC 822) specifies that dots in phrases are
        # obsolete syntax, which conforming programs MUST recognize but NEVER
        # generate (see $4.1 Miscellaneous obsolete tokens).  This is a
        # departure from RFC 822 which did not allow dots in non-quoted
        # phrases.
        self.check('To: User J. Person <person@dom.ain>\n\n',
                   [('User J. Person', 'person@dom.ain')])

test_support.run_unittest(MessageTestCase)
<|endoftext|>


<commit_before>from thinglang.compiler import BytecodeSymbols
from thinglang.compiler.indexer import ResolvedReference
from thinglang.lexer.tokens.base import LexicalAccess, LexicalIdentifier
from thinglang.lexer.tokens.functions import LexicalClassInitialization
from thinglang.parser.symbols import BaseSymbol, DefinitionPairSymbol
from thinglang.parser.symbols.collections import ListInitializationPartial, ListInitialization
from thinglang.utils.type_descriptors import ValueType

class Access(BaseSymbol):
    def __init__(self, slice):
        super(Access, self).__init__(slice)
        self.target = [x for x in slice if not isinstance(x, LexicalAccess)]
        self.type = None

    def evaluate(self, resolver):
        return resolver.resolve(self)

    def describe(self):
        return '{}:{}'.format('.'.join(str(x) for x in self.target), self.type)

    def __getitem__(self, item):
        return self.target[item]

    def __eq__(self, other):
        return type(self) == type(other) and self.target == other.target

    @classmethod
    def create(cls, target):
        return cls([LexicalIdentifier(x) if not isinstance(x, LexicalIdentifier) else x for x in target])

    def transpile(self):
        #if self.target[0].is_self():
        #    return self.target[0].transpile() + '->' + '->'.join(x.transpile() for x in self.target[1:])

        return '->'.join(x.transpile() for x in self.target)

    def type_id(self):
        return None

class ArgumentListPartial(ListInitializationPartial):
    pass

class ArgumentListDecelerationPartial(ArgumentListPartial):
    STRICTLY_TYPED = True
    pass

class ArgumentList(ListInitialization):
    pass

class MethodCall(BaseSymbol, ValueType):
    def __init__(self, slice):
        super(MethodCall, self).__init__(slice)
        self.value = self

        if isinstance(slice[0], LexicalClassInitialization):
            self.target = Access([slice[1], LexicalIdentifier.constructor().set_context(slice[0])])
            self.arguments = slice[2]
            self.constructing_call = True
        else:
            self.target, self.arguments = slice
            self.constructing_call = False

        if not self.arguments:
            self.arguments = ArgumentList()

        self.resolved_target = None

    def describe(self):
        return 'target={}, args={}'.format(self.target, self.arguments)

    def replace(self, original, replacement):
        self.arguments.replace(original, replacement)

    def references(self):
        return self.target, self.arguments

    @classmethod
    def create_constructing_call(cls, target, arguments=None):
        return cls([LexicalClassInitialization(None), target, arguments if arguments is not None else ArgumentList()])

    @classmethod
    def create(cls, target, arguments=None):
        return cls([Access.create(target), arguments])

    def transpile(self, orphan=True):
        return f'{self.target.transpile()}({self.arguments.transpile()}){";" if orphan else ""}'

    def statics(self):
        yield from self.arguments.statics()

    def compile(self, context, captured=False):

        for arg in reversed(self.arguments):
            context.push_down(arg)

        if self.target[0].is_self():
            context.append(BytecodeSymbols.call(*self.resolved_target.index))
            if not captured:
                context.append(BytecodeSymbols.pop())  # pop the return value, if the method does not return

        else:
            context.append(BytecodeSymbols.call_internal(3, 0))

    def type_id(self):
        return self.resolved_target.type

class ReturnStatement(BaseSymbol):
    def __init__(self, slice):
        super().__init__(slice)
        self.value = slice[1] if len(slice) == 2 else None

    def transpile(self):
        if self.value:
            return 'return Thing(new this_type({}));'.format(self.value.transpile())
        else:
            return 'return NULL;'

    def compile(self, context):
        context.push_down(self.value)
        context.append(BytecodeSymbols.returns())<commit_msg>Removed the (3,0) hack (finally!)<commit_after>from thinglang.compiler import BytecodeSymbols
from thinglang.compiler.indexer import ResolvedReference
from thinglang.lexer.tokens.base import LexicalAccess, LexicalIdentifier
from thinglang.lexer.tokens.functions import LexicalClassInitialization
from thinglang.parser.symbols import BaseSymbol, DefinitionPairSymbol
from thinglang.parser.symbols.collections import ListInitializationPartial, ListInitialization
from thinglang.utils.type_descriptors import ValueType

class Access(BaseSymbol):
    def __init__(self, slice):
        super(Access, self).__init__(slice)
        self.target = [x for x in slice if not isinstance(x, LexicalAccess)]
        self.type = None

    def evaluate(self, resolver):
        return resolver.resolve(self)

    def describe(self):
        return '{}:{}'.format('.'.join(str(x) for x in self.target), self.type)

    def __getitem__(self, item):
        return self.target[item]

    def __eq__(self, other):
        return type(self) == type(other) and self.target == other.target

    @classmethod
    def create(cls, target):
        return cls([LexicalIdentifier(x) if not isinstance(x, LexicalIdentifier) else x for x in target])

    def transpile(self):
        #if self.target[0].is_self():
        #    return self.target[0].transpile() + '->' + '->'.join(x.transpile() for x in self.target[1:])

        return '->'.join(x.transpile() for x in self.target)

    def type_id(self):
        return None

class ArgumentListPartial(ListInitializationPartial):
    pass

class ArgumentListDecelerationPartial(ArgumentListPartial):
    STRICTLY_TYPED = True
    pass

class ArgumentList(ListInitialization):
    pass

class MethodCall(BaseSymbol, ValueType):
    def __init__(self, slice):
        super(MethodCall, self).__init__(slice)
        self.value = self

        if isinstance(slice[0], LexicalClassInitialization):
            self.target = Access([slice[1], LexicalIdentifier.constructor().set_context(slice[0])])
            self.arguments = slice[2]
            self.constructing_call = True
        else:
            self.target, self.arguments = slice
            self.constructing_call = False

        if not self.arguments:
            self.arguments = ArgumentList()

        self.resolved_target = None
        self.internal = False

    def describe(self):
        return 'target={}, args={}'.format(self.target, self.arguments)

    def replace(self, original, replacement):
        self.arguments.replace(original, replacement)

    def references(self):
        return self.target, self.arguments

    @classmethod
    def create_constructing_call(cls, target, arguments=None):
        return cls([LexicalClassInitialization(None), target, arguments if arguments is not None else ArgumentList()])

    @classmethod
    def create(cls, target, arguments=None):
        return cls([Access.create(target), arguments])

    def transpile(self, orphan=True):
        return f'{self.target.transpile()}({self.arguments.transpile()}){";" if orphan else ""}'

    def statics(self):
        yield from self.arguments.statics()

    def compile(self, context, captured=False):

        for arg in reversed(self.arguments):
            context.push_down(arg)

        if self.internal:
            context.append(BytecodeSymbols.call_internal(*self.resolved_target.index))
        else:
            context.append(BytecodeSymbols.call(*self.resolved_target.index))

        if not captured:
            context.append(BytecodeSymbols.pop())  # pop the return value, if the method does not return

    def type_id(self):
        return self.resolved_target.type

class ReturnStatement(BaseSymbol):
    def __init__(self, slice):
        super().__init__(slice)
        self.value = slice[1] if len(slice) == 2 else None

    def transpile(self):
        if self.value:
            return 'return Thing(new this_type({}));'.format(self.value.transpile())
        else:
            return 'return NULL;'

    def compile(self, context):
        context.push_down(self.value)
        context.append(BytecodeSymbols.returns())<|endoftext|>


<commit_before>import json
from collections import OrderedDict

LENGTH_FIELD_LENGTH = 4

def serialize(json_obj):
    '''Turn a JSON object into bytes suitable for writing out to the network.
    Includes a fixed-width length field to simplify reconstruction on the other
    end of the wire.'''
    while True:
        obj = json.dumps(json_obj)
        b = obj.encode()
        encoded = (len(b)+LENGTH_FIELD_LENGTH).to_bytes(LENGTH_FIELD_LENGTH,byteorder='little') + b
        return encoded
    # except:
        # print('Invalid JSON object received:\n'+str(json_obj))
        # return None

class Deserializer(object):
    '''A buffering and bytes-to-json engine.
    Data can be received in arbitrary chunks of bytes, and we need a way to
    reconstruct variable-length JSON objects from that interface. This class
    buffers up bytes until it can detect that it has a full JSON object (via
    a length field pulled off the wire). To use this, shove bytes in with the
    append() function and call ready() to check if we've reconstructed a JSON
    object. If True, then call deserialize to return it. That object will be
    removed from this buffer after it is returned.'''

    def __init__(self):
        self.buf = b''
        self.buflen = -1

    def append(self, data):
        self.buf += data
        self._maybe_set_length()

    def _maybe_set_length(self):
        if self.buflen < 0 and len(self.buf) >= LENGTH_FIELD_LENGTH:
            self.buflen = int.from_bytes(self.buf[0:LENGTH_FIELD_LENGTH], byteorder="little")

    def ready(self):
        return (self.buflen > 0 and len(self.buf) >= self.buflen)

    def deserialize(self):
        json_str = self.buf[LENGTH_FIELD_LENGTH:self.buflen].decode()
        self.buf = self.buf[self.buflen:]
        self.buflen = -1
        # There may be more data in the buffer already, so preserve it
        self._maybe_set_length()
        try:
            #Note how now everything is assumed to be an OrderedDict
            obj = json.loads(json_str, object_pairs_hook=OrderedDict)
            #print("OBJ", obj)
            return obj
        except json.JSONDecodeError:
            print('Invalid JSON object received:\n'+str(json_str))
            return None
<commit_msg>Revert "The changed serialization file that matches with the server error log"<commit_after>import json
from collections import OrderedDict

LENGTH_FIELD_LENGTH = 4

def serialize(json_obj):
    '''Turn a JSON object into bytes suitable for writing out to the network.
    Includes a fixed-width length field to simplify reconstruction on the other
    end of the wire.'''
    try:
        obj = json.dumps(json_obj)
        b = obj.encode()
        encoded = (len(b)+LENGTH_FIELD_LENGTH).to_bytes(LENGTH_FIELD_LENGTH,byteorder='little') + b
        return encoded
    except:
        print('Invalid JSON object received:\n'+str(json_obj))
        return None

class Deserializer(object):
    '''A buffering and bytes-to-json engine.
    Data can be received in arbitrary chunks of bytes, and we need a way to
    reconstruct variable-length JSON objects from that interface. This class
    buffers up bytes until it can detect that it has a full JSON object (via
    a length field pulled off the wire). To use this, shove bytes in with the
    append() function and call ready() to check if we've reconstructed a JSON
    object. If True, then call deserialize to return it. That object will be
    removed from this buffer after it is returned.'''

    def __init__(self):
        self.buf = b''
        self.buflen = -1

    def append(self, data):
        self.buf += data
        self._maybe_set_length()

    def _maybe_set_length(self):
        if self.buflen < 0 and len(self.buf) >= LENGTH_FIELD_LENGTH:
            self.buflen = int.from_bytes(self.buf[0:LENGTH_FIELD_LENGTH], byteorder="little")

    def ready(self):
        return (self.buflen > 0 and len(self.buf) >= self.buflen)

    def deserialize(self):
        json_str = self.buf[LENGTH_FIELD_LENGTH:self.buflen].decode()
        self.buf = self.buf[self.buflen:]
        self.buflen = -1
        # There may be more data in the buffer already, so preserve it
        self._maybe_set_length()
        try:
            #Note how now everything is assumed to be an OrderedDict
            obj = json.loads(json_str, object_pairs_hook=OrderedDict)
            #print("OBJ", obj)
            return obj
        except json.JSONDecodeError:
            print('Invalid JSON object received:\n'+str(json_str))
            return None
<|endoftext|>


<commit_before>from django.contrib import admin
from django.template.defaultfilters import mark_safe
from django.utils import timezone

from . import models

class GCMDeviceAdmin(admin.ModelAdmin):
    list_display = (
        'user_email', 'user_username', 'regid', 'device_name', 'is_active',
        'created_on',
    )
    list_filter = ('is_active', )
    search_fields = [
        'user__username', 'user__first_name', 'user__last_name', 'user__email',
        'registration_id', 'device_name',
    ]
    readonly_fields = ('device_name', 'registration_id')

    def user_username(self, obj):
        return obj.user.username

    def user_email(self, obj):
        return obj.user.email

    def regid(self, obj):
        """registration id, teaser."""
        return ''.join([obj.registration_id[:20], "..."])

admin.site.register(models.GCMDevice, GCMDeviceAdmin)

class GCMMessageAdmin(admin.ModelAdmin):
    list_display = (
        'user_email', 'user_username', 'title', 'message_teaser',
        'deliver_on', 'success', 'created_on',
    )
    list_filter = ('success', 'response_code')
    search_fields = [
        'user__username', 'user__first_name', 'user__last_name', 'user__email',
        'message_id', 'title', 'message'
    ]
    exclude = ('response_text', )
    readonly_fields = (
        'message_id', 'success', 'response_code', 'gcm_response', 'expire_on',
        'registration_ids', 'created_on',
    )
    actions = ['send_notification', 'expire_messages']

    def registration_ids(self, obj):
        """List all the registration IDs for the message's user."""
        if obj.user:
            ids = obj.user.gcmdevice_set.values_list("registration_id", flat=True)
            ids = "\n".join(ids)
            return mark_safe("
{0}
".format(ids))
        return ''
    registration_ids.short_description = "Registration IDs"
    registration_ids.allow_tags = True

    def gcm_response(self, obj):
        """Formatting for the response_text that GCM sets."""
        return mark_safe("
{0}
".format(obj.response_text))
    gcm_response.short_description = "GCM Response"
    gcm_response.allow_tags = True

    def message_teaser(self, obj):
        return "{0}...".format(obj.message[:32])

    def user_username(self, obj):
        return obj.user.username

    def user_email(self, obj):
        return obj.user.email

    def send_notification(self, request, queryset):
        for obj in queryset:
            obj.send()
    send_notification.short_description = "Send Message via GCM"

    def expire_messages(self, request, queryset):
        queryset = queryset.filter(expire_on__lte=timezone.now())
        queryset.delete()
    expire_messages.short_description = "Remove Expired Messages"

admin.site.register(models.GCMMessage, GCMMessageAdmin)
<commit_msg>displaying more GCM debug info in the admin<commit_after>from pprint import pformat

from django.contrib import admin
from django.template.defaultfilters import mark_safe
from django.utils import timezone

from . import models

class GCMDeviceAdmin(admin.ModelAdmin):
    list_display = (
        'user_email', 'user_username', 'regid', 'device_name', 'is_active',
        'created_on',
    )
    list_filter = ('is_active', )
    search_fields = [
        'user__username', 'user__first_name', 'user__last_name', 'user__email',
        'registration_id', 'device_name',
    ]
    readonly_fields = ('device_name', 'registration_id')

    def user_username(self, obj):
        return obj.user.username

    def user_email(self, obj):
        return obj.user.email

    def regid(self, obj):
        """registration id, teaser."""
        return ''.join([obj.registration_id[:20], "..."])

admin.site.register(models.GCMDevice, GCMDeviceAdmin)

class GCMMessageAdmin(admin.ModelAdmin):
    list_display = (
        'user_email', 'user_username', 'title', 'message_teaser',
        'deliver_on', 'success', 'created_on',
    )
    list_filter = ('success', 'response_code')
    search_fields = [
        'user__username', 'user__first_name', 'user__last_name', 'user__email',
        'message_id', 'title', 'message'
    ]
    exclude = ('response_text', 'registration_ids', 'response_data')
    readonly_fields = (
        'message_id', 'success', 'response_code', 'gcm_response',
        'pretty_response_data', 'delivered_to', 'registered_devices',
        'created_on', 'expire_on',
    )
    actions = ['send_notification', 'expire_messages']

    def pretty_response_data(self, obj):
        """pretty-printed response data"""
        data = pformat(obj.response_data)
        return mark_safe("
{0}
".format(data))
    pretty_response_data.short_description = "GCM Response Data"
    pretty_response_data.allow_tags = True

    def delivered_to(self, obj):
        """This is the list of registration_ids that we get back from GCM
        after sending the message"""
        return mark_safe("
{0}
".format(obj.registration_ids))
    delivered_to.short_description = "Delivered to"
    delivered_to.allow_tags = True

    def registered_devices(self, obj):
        """List all the registration IDs owned by the user."""
        if obj.user:
            ids = "\n".join(obj.registered_devices)
            return mark_safe("
{0}
".format(ids))
        return ''
    registered_devices.short_description = "Registered Devices"
    registered_devices.allow_tags = True

    def gcm_response(self, obj):
        """Formatting for the response_text that GCM sets."""
        return mark_safe("
{0}
".format(obj.response_text))
    gcm_response.short_description = "GCM Response"
    gcm_response.allow_tags = True

    def message_teaser(self, obj):
        return "{0}...".format(obj.message[:32])

    def user_username(self, obj):
        return obj.user.username

    def user_email(self, obj):
        return obj.user.email

    def send_notification(self, request, queryset):
        for obj in queryset:
            obj.send()
    send_notification.short_description = "Send Message via GCM"

    def expire_messages(self, request, queryset):
        queryset = queryset.filter(expire_on__lte=timezone.now())
        queryset.delete()
    expire_messages.short_description = "Remove Expired Messages"

admin.site.register(models.GCMMessage, GCMMessageAdmin)
<|endoftext|>