Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Release 0.14 #238

Closed
asvetlov opened this issue Jan 13, 2015 · 31 comments
Closed

Release 0.14 #238

asvetlov opened this issue Jan 13, 2015 · 31 comments
Labels

Comments

@asvetlov
Copy link
Member

I used to wish implementing websocket high-level client in 0.14 but has switched to another issues (multidicts etc.)

I think we are almost ready to publishing new release now.

I need to write some tests to improve multidict coverage first -- and after that we are ready.

We have a good portion of improvements and fixes to make new release.

Are you agree?

@fafhrd91
Copy link
Member

i'd like to do refactoring on transfer-encoding support for this release, otherwise i'm happy with 0.14 feature list

@ludovic-gasc
Copy link
Contributor

I've something I'll really need soon: CORS middleware.
Could I propose a pull request for that, or do you already have something in your pipe?

@asvetlov
Copy link
Member Author

@GMLudo I'd like to see CORS middleware in separate project.
It should be named aiohttp_cors and I'll create it very soon by porting aiorest code.

As other option you may start your own aiohttp_cors implementation just now, we can transfer repo ownership to aio-libs with granting commit rights for that project to you.
But, please, in this case follow the rule: no any significant change without Pull Request.
We are keeping high quality for published aio-libs libraries.

Personally I like the second but, dont get me wrong, your proposals for aiorest was not always good.

@asvetlov
Copy link
Member Author

@fafhrd91 I don't follow.
I've read you message with link to http://lists.w3.org/Archives/Public/ietf-http-wg/2014JulSep/1710.html
But I don't understand

@asvetlov btw in that way we can implement custom aiohttp.web chunked
encoding

Would you elaborate?

@ludovic-gasc
Copy link
Contributor

@asvetlov Don't worry, I'm not as experimented as you: I'm not an AsyncIO contributor nor Python core developer, I'm a simple dev guy ;-)
Thanks to propose me ownership for aiohttp_cors, but, you've implemented CORS in aiorest, I think it will be more efficient if could be you the first owner. If after, I've made an enough important contribution in aiohttp_cors, it will be a pleasure to be a maintainer.

BTW, I've some potential PRs for aiohttp: the first one should me to move this small Response class helper in aiohttp.web: https://github.com/Eyepea/API-Hour/blob/master/api_hour/plugins/aiohttp/__init__.py#L8
It's the aiohttp.web server side equivalent of .json() coroutine of aiohttp.client, we use that a lot.
What's your opinion ?

@asvetlov
Copy link
Member Author

@GMLudo

Thanks for very high belief in my skills, but CORS author is @popravich BTW.

We don't inherit from Response but use render_json decorator for web handlers:

def render_json(func):
    assert asyncio.iscoroutinefunction(func), func

    @asyncio.coroutine
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        ret = yield from func(*args, **kwargs)
        if isinstance(ret, Cliche):
            ret = ret.as_dict()
        try:
            text = dumps(ret)
        except TypeError:
            raise RuntimeError("{!r} result {!r} is not serializable".format(
                func, ret))
        return web.Response(text=text, content_type='application/json')

    return wrapper

Cliche is our wrapper for https://github.com/Deepwalker/trafaret library, we've found it very useful for validations (json and other dict-like data):

import abc
import trafaret as t


_empty = object()


class ClicheMeta(abc.ABCMeta):

    def __init__(self, name, bases, dic):
        traf = dic.get('trafaret')
        if traf is not None:
            traf.append(self)


class Cliche(metaclass=ClicheMeta):
    """Utility class allowing to create classes with trafaret.

    Usage example:

    >>> class User(Cliche):
    ...     trafaret = t.Dict({
    ...         t.Key('uid'): t.Int,
    ...         t.Key('username'): t.String,
    ...         t.Key('flags'): t.Mapping(
    ...             t.String, t.Bool),
    ...         })
    >>> user = User(uid=1, username='Me', flags={'admin': True})
    >>> user.as_dict()
    {'uid': 1, 'username': 'Me', 'flags': {'admin': True}}
    """

    trafaret = None

    def __init__(self, data=None, **kw):
        if data is None:
            data = self.trafaret.check_and_return(kw)
        self.__dict__.update(data)

    def as_dict(self):
        """Returns dict representation of object."""
        res = {}
        for key in self.trafaret.keys:
            name = key.get_name()
            val = getattr(self, name, _empty)
            if val is _empty:
                if key.optional:
                    continue
                raise AttributeError("{} has no {!r} attribute".format(
                    self.__class__.__name__, name))
            res[name] = dump(val, key.trafaret)
        return res

    def update(self, key, value):
        names = [x.get_name() for x in self.trafaret.keys]
        if key in names:
            setattr(self, key, value)
        else:
            raise AttributeError("{} has no {!r} attribute".format(
                self.__class__.__name__, key))


def dump(obj, traf):
    if isinstance(obj, Cliche):
        return obj.as_dict()
    elif isinstance(traf, t.List):
        return [dump(val, traf.trafaret) for val in obj]
    elif isinstance(traf, t.Tuple):
        return tuple(dump(val, tr) for val, tr in zip(obj, traf.trafarets))
    elif isinstance(traf, t.Mapping):
        return {key: dump(val, traf.value)
                for key, val in obj.items()}
    elif isinstance(traf, t.Dict):
        keys = {key.get_name(): key.trafaret
                for key in traf.keys}
        return {key: dump(val, keys.get(key, t.Any))
                for key, val in obj.items()}
    else:
        return obj

@fafhrd91
Copy link
Member

i’ll remove implicit chunking from HttpMessage.

On Jan 13, 2015, at 12:40 PM, Andrew Svetlov notifications@github.com wrote:

@fafhrd91 https://github.com/fafhrd91 I don't follow.
I've read you message with link to http://lists.w3.org/Archives/Public/ietf-http-wg/2014JulSep/1710.html http://lists.w3.org/Archives/Public/ietf-http-wg/2014JulSep/1710.html
But I don't understand

@asvetlov https://github.com/asvetlov btw in that way we can implement custom aiohttp.web chunked
encoding

Would you elaborate?


Reply to this email directly or view it on GitHub #238 (comment).

@asvetlov
Copy link
Member Author

@fafhrd91 That sounds good but please make changes in separate branch and after that make a Pull Request.

I believe in your expertise but want to see the whole required commits in the single place.

@fafhrd91
Copy link
Member

sure

On Jan 13, 2015, at 1:42 PM, Andrew Svetlov notifications@github.com wrote:

@fafhrd91 https://github.com/fafhrd91 That sounds good but please make changes in separate branch and after that make a Pull Request.

I believe in your expertise but want to see the whole required commits in the single place.


Reply to this email directly or view it on GitHub #238 (comment).

@ludovic-gasc
Copy link
Contributor

Hi @asvetlov,

About render_json decorator, it's an interesting approach to identify easily each type of your handler directly in your code.
Nevertheless, I'm not a Python expert and I'm very happy if you have a good tip for that, but, sometimes, I need to "change" the decorator depends on the computation I do in handler.

Two concrete examples to describe my problem:

  1. I've a WebService to deliver phone calls details. Depends on the Accept header, I will return JSON, CSV or XML.
  2. I've built a provisioning server, based on aiohttp, to configure automatically phone devices. Based on User-Agent header of HTTP request from the phone, I generate a config file very different: XML, INI, Binary, HTML (it's not a joke, a phone brand use HTML file to embed settings).

With decorator approach, how to handle that ?

About Trafadet, I've already add this library in my todo-list when you spoke about that with Guido.
I'm interested in to use that with WebServices, I always need to validate data.
Thanks for Cliche snippet, I'll test that.
BTW, you could maybe made a sample aiohttp.web handler in examples/ folder to show that.

@fafhrd91
Copy link
Member

@GMLudo i suggest to make handler like router, so you can create route for path and then extra resolve based on extra parameters like "Accept" and "User-Agent"

@ludovic-gasc
Copy link
Contributor

@fafhrd91 I see two problems with this approach:

  1. I need to split my business logic in two parts
  2. Sorry, but for my point of view, it's a lot more complicated to do that compare to a if that returns a subclass of Response or a Response itself.
    When it's possible, I prefer to keep things simple for me, for my coworkers, and certainly for my future me who he won't remember why I've did that ;-)

@asvetlov
Copy link
Member Author

@GMLudo I'm with @fafhrd91

You may define the second layer on route resolving.

It may looks like (untested, I just show the idea):

class Handler:

    def __init__(self):
        self._accepts = {}

    @asyncio.coroutine
    def do_route(self, request):
        acceptor = self._accepts.get(request.headers.get('ACCEPT'))
        if acceptor is None:
            raise HTTPNotAcceptable()
        return yield from acceptor(request)

    def reg_acceptor(self, accept, handler):
        self._accepts[accept] = handler


def handle_json(request):
    # do handling

handler = Handler()
app.router.add_route('GET', '/', handler.do_route)
handler.reg_acceptor('application/json', handle_json)

@ludovic-gasc
Copy link
Contributor

Hi @asvetlov and @fafhrd91,

Thanks for the snippet, you give me a good idea.
BTW, in case of you'll be present for Python-FOSDEM, I'll buy you a beer during Python drink ;-)

@asvetlov
Copy link
Member Author

Sorry, I'll have a talk about aiohttp at by.pycon.org at the same days.
But I'd like to visit the next US PyCon at least.

@asvetlov
Copy link
Member Author

@GMLudo i've added the snippet into web documentation: 52c4e5e

@ludovic-gasc
Copy link
Contributor

Ok, thank you.

@mwfrojdman
Copy link
Contributor

Hi,
I've been using aiohttp for some time now and find especially the minimal server library really useful! Especially the triviality of handling long polling and plugging in 3rd party routing libraries (I use werkzeug's rules and converters previously employed in an WSGI environment).

I noticed that there's a Cython module _multidict.pyx. Is the header handling performance so critical that an extension module is needed? Past experience has shown that extension modules that need to be compiled are especially problematic on Windows, but depending on the circumstances on other platforms too. It may reduce the spreading of the library if it contains, or worse, requires hard to install dependencies.

@fafhrd91
Copy link
Member

@mwfrojdman extension module is optional, aiohttp should work without _multidict extension.

@ludovic-gasc
Copy link
Contributor

_multidict extension isn't necessary, I've already tested that.

@fafhrd91
Copy link
Member

i'm done with chunked encoding.
only #244 is a blocker for 0.14 release

@fafhrd91
Copy link
Member

new blocker #246, i'd like to fix it or at least understand implications before 0.14 release

@asvetlov
Copy link
Member Author

Ok. Just a note: I've done all my work (including documentation updating).

@asvetlov
Copy link
Member Author

Should we still upload wheels to PyPI?
I may generate wheel files for Linux and Windows for 32 and 64 bits and Python 3.3 and 3.4, but it requires extra work.

@fafhrd91
Copy link
Member

it is up to you. i don't have any windows machine nearby

@fafhrd91
Copy link
Member

@asvetlov i think we are done with 0.14 release. do you mind make a release?

@asvetlov
Copy link
Member Author

Sure. Starting to do.

Personally I think 0.14 is the best release for last months: we've done a hard work to make aiohttp.web really ready for common usage. I mean a lot of tiny changes and code cleanups.

I have the strong feel the aiohttp.web code has stabilized now.

Almost all new wish appeared in my mind may be implemented by current code with third-party libraries: CORS, sessions, authorization, rendering etc.

I assume we have very strong and scalable design now.

Thanks for all contributors.

@asvetlov
Copy link
Member Author

Done.

@fafhrd91
Copy link
Member

Awesome! I agree 0.14 is best release so far

On Thursday, January 15, 2015, Andrew Svetlov notifications@github.com
wrote:

Closed #238 #238.


Reply to this email directly or view it on GitHub
#238 (comment).

@asvetlov
Copy link
Member Author

Sorry, I've missed to tag 0.14.0 in version, so I've have to make 0.14.1 release also.

@lock
Copy link

lock bot commented Oct 29, 2019

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that new issue.

@lock lock bot added the outdated label Oct 29, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants