We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Morepath: a Python Web Framework with Super Powers

00:00

Formal Metadata

Title
Morepath: a Python Web Framework with Super Powers
Title of Series
Part Number
104
Number of Parts
119
Author
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language
Production PlaceBerlin

Content Metadata

Subject Area
Genre
Abstract
Martijn Faassen - Morepath: a Python Web Framework with Super Powers Morepath is a server web framework written with modern, rich client web development in mind. Why another new Python web framework in 2014? Because it can be done better: Morepath understands how to construct hyperlinks from models. Writing a generic view in Morepath is like writing any other view. With Morepath, you can reuse, extend and override apps as easily as you can construct them. Even if you don't end up using Morepath, you will learn something about how the nature of web frameworks. ----- Morepath is a new server web framework written with modern, rich client web development in mind. In the talk I will be discussing some core features of Morepath that make it different: * Its different take on routing and linking. Morepath has support to help you construct hyperlinks to models. * Its view system: plain views, generic views, view composition. * Morepath's approach to application construction allows application extension and overriding, and composition. This talk will attempt to convince people to try Morepath. For those unable or unwilling to try, I will communicate some design principles behind Morepath which can be of help to any web developer.
Keywords
80
Thumbnail
25:14
107
Thumbnail
24:35
CodeGoogolInheritance (object-oriented programming)World Wide Web ConsortiumComputer virusPresentation of a groupTouchscreenSpacetimeComputer animationLecture/Conference
World Wide Web ConsortiumSoftware developerSineTime zoneMetropolitan area networkRoutingGastropod shellWorld Wide Web ConsortiumContrast (vision)Software frameworkOrder (biology)CuboidDiagram
GenderWorld Wide Web ConsortiumSoftware frameworkContrast (vision)Configuration spaceLecture/ConferenceComputer animation
BitTime zoneQuicksortMoment (mathematics)FeedbackMultiplication signBinary imagePerformance appraisalInheritance (object-oriented programming)Lecture/Conference
World Wide Web ConsortiumFront and back endsJava appletScripting languageMusical ensembleWeb browserWhiteboardFront and back endsPhysical systemCartesian coordinate systemQuicksortWorld Wide Web ConsortiumEndliche ModelltheorieComputer animation
Asynchronous Transfer ModeQuicksortBlock (periodic table)Parameter (computer programming)Order (biology)AverageDifferent (Kate Ryan album)Normal (geometry)View (database)Lecture/Conference
RoutingMereologyEvent horizonMultiplication signLattice (order)AreaCodeSlide ruleRoutingComputer-assisted translationComputer animation
RoutingRoutingArithmetic meanQuicksortRepresentation (politics)Error messageDatabaseSoftware frameworkComputer-assisted translationServer (computing)World Wide Web ConsortiumLecture/ConferenceComputer animation
World Wide Web ConsortiumCASE <Informatik>Functional (mathematics)HypothesisQuicksortSoftware frameworkCodeServer (computing)DatabaseRoutingLecture/Conference
Server (computing)RoutingIntelMetropolitan area networkData modelAsynchronous Transfer ModeDenial-of-service attackLink (knot theory)World Wide Web ConsortiumMathematicsMaxima and minimaMetreArithmetic logic unitBeat (acoustics)Uniform resource locatorData typeParameter (computer programming)CodeSocial classQuery languageLink (knot theory)View (database)Parameter (computer programming)Default (computer science)InformationInheritance (object-oriented programming)Computer-assisted translationOrder (biology)Electronic mailing listEndliche ModelltheorieLine (geometry)Video gameRoutingObject (grammar)MathematicsFunctional (mathematics)Generic programmingRepresentation (politics)Physical systemWorld Wide Web ConsortiumServer (computing)QuicksortMechanism designClient (computing)Drop (liquid)Instance (computer science)CASE <Informatik>Error messageMultiplicationSoftware frameworkGoodness of fitMereologyTemplate (C++)FreewareString (computer science)Cartesian coordinate systemUniform resource locatorTimestampWebsiteWebdesignWeb applicationNormal (geometry)Exception handlingDifferent (Kate Ryan album)Scaling (geometry)HypermediaObject-relational mappingForm (programming)BitType theoryCAN busElectric generatorObservational studyDependent and independent variablesSystem callAlpha (investment)DemosceneAreaPressureRight angleGraph (mathematics)Uniqueness quantificationBit rateTranslation (relic)Software developerPerfect groupWritingRoboticsOntologyArithmetic progressionGroup actionDatabaseComputer animation
Data acquisitionExecutive information systemMultiplicationMusical ensembleMetropolitan area networkDenial-of-service attackExtension (kinesiology)Asynchronous Transfer ModeInclusion mapModulo (jargon)Grand Unified TheoryPhysical systemEmailUniform resource locatorDisintegrationStatisticsRegulärer Ausdruck <Textverarbeitung>Discrete element methodCodeLink (knot theory)QuicksortCodeCartesian coordinate systemSystem callBitDefault (computer science)SubsetElectric generatorRevision controlFunction (mathematics)Functional (mathematics)Raw image formatWikiPhysical systemInformationObject (grammar)ImplementationForm (programming)Data conversionMechanism designReal numberVideo gameGeneric programmingServer (computing)Extension (kinesiology)DatabaseSet (mathematics)Core dumpSocial classSpacetimeRepresentation (politics)Endliche ModelltheorieOverhead (computing)Exception handlingUniform resource locatorSoftware frameworkPrimitive (album)Context awarenessModule (mathematics)Library (computing)View (database)DataflowOrder (biology)Database transactionWorld Wide Web ConsortiumInteractive televisionTerm (mathematics)RoutingINTEGRALComputer architectureEmailComputer-assisted translationInheritance (object-oriented programming)Connectivity (graph theory)Mobile appRule of inferencePlug-in (computing)Proxy serverIdentity managementSoftware testingComputer fileFluid staticsCache (computing)Electronic mailing listTable (information)String (computer science)Predicate (grammar)Link (knot theory)Probability density functionMiddlewareDifferent (Kate Ryan album)Slide ruleImage registrationError messageNumberBuildingCoefficient of determinationData typeLevel (video gaming)Software developerScripting languageFamily of setsReading (process)WebsiteWeb pageMereologyInterface (computing)BenchmarkParameter (computer programming)Information systemsWeb applicationRight angleCycle (graph theory)Natural numberVulnerability (computing)Direction (geometry)FrustrationMathematicsVector potentialArithmetic progressionCuboidComputer animation
Extension (kinesiology)Link (knot theory)Price indexMultiplication signSoftware developerCartesian coordinate systemQuicksortPlanningStability theoryAuthenticationCodeProjective planeRight angleMathematicsReal numberMassVector potentialInstance (computer science)Insertion lossMereologySpeech synthesisDatabaseBuildingSet (mathematics)Social classStandard deviationLecture/Conference
GoogolCode
Transcript: English(auto-generated)
Hello, you'll have to bear with me, the presentation will definitely fit on this screen because I adjusted it for 700 and it's 1900, so I have a lot of extra space now.
So who am I? Well, I was ready to introduce just now, been doing a lot of stuff and most recently more path. So why would somebody create a new web framework in 2014, I started in 2013, I'm gonna try
to show you why you can still do new things with more or less traditional routing web frameworks. And in order to do so, I have to contrast more path with other Python web frameworks.
So I'm gonna do like a laundry detergent commercial, you know, when the stuff you put in your washer, you put this white powder in and in the traditional commercial for that you have like the shiny box there and you have the evil brand X which really sucks. So I'm gonna be this annoying sales guy who's gonna tell you all that the shining
box is awesome and brand X is horrible. So yeah, brand X, what do you mean with brand X? Brand X is one of the popular routing web frameworks in Python that you probably use, I will not name them.
And by this talk you might learn something about more path, but also more about brand X, because the contrast works both ways. That might benefit you as well. And I really won't name brand X, okay, could be bottle or flask or Django or pyramid
in its most common configuration, pyramid is kind of special, they're all special and they all have their benefits, I'm not trying to put them down, I'm just contrasting. And of course I'm gonna say that brand X sucks and I'm better with more path and all that, but, and pyramid is especially special and I learned a lot from it, we
are users of brand X web framework, like routing and fuse and stuff, yeah, lots of people. So a little bit about the more path origins, I won't go into this very deeply, so this is exploding planet Zope, and just at the last moment they shoot out this sort
of hero with super powers, as long as you're not exposed to all pieces of the planet Zope, right, that's really bad. So they shoot it out. That's actually not the first thing they shot out, they already shot out a whole pyramid
before. It was only crumbling then, but you know the pyramid people were a bit smarter, they sort of crumbled earlier, but anyway, we just got out in time, it's okay. And the Zope pieces are really easy to recognize because they sort of have this weird alien green glow, so it's simple. Anyway, so what are the goals of more path?
More path is focused on the modern web, and the modern web means REST and it means rich JavaScript-based client-side applications run in the browser that use some kind of REST backend. And more path tries to be easy to develop with, to be powerful, so that when you are sort of trying to do something more sophisticated, you can still do it, and it tries to be small
as well, because it needed to be embedded in an existing system that didn't want to take too much on board. So yeah, I claim that more path has super powers, it looks like sort of this innocent Clark Kent guy who definitely doesn't have super powers on the outside, so it looks like your average flask or something, and then he pulls open his shirt and then suddenly
the super powers come out. And it's important to realize that the super powers of more path are not a different mode of working. Clark Kent actually has those super powers too, and doing the normal Clark Kent things, you know, routing and views and all that stuff in more path, automatically sort of
doing the super things is sort of doing more of the same. So you only need to learn the primitives, you don't need to learn something new in order to use those super powers. So I'm going to discuss three topics, I'm going to compare routing with brand X, I'm going to compare linking more path linking with brand X, and I'm going to talk about
reuse in more path, like how you reuse code. So let's discuss routing. So we have a route URL path, and it goes to a cat. If you're hoping for more beautifully drawn pictures, I didn't have enough time to make more, so we're going to get boring slides now.
So, you know, it takes time to draw that well. So anyway, so we have a route to a cat, and, you know, that sort of means get representation of an animal with the ID cat in a typical routing framework. And we have one extra requirement, if the cat ID does not exist in the database or
whatever, then we want to get a 404 not found error from our web server. It's a pretty simple case. So this is what you do in a sort of typical, I mean, this is hypothetical code, but it's sort of what you typically do in a brand X framework. You declare some kind of route with a variable in there, it's ID there, and then ID is used in a function that does two things.
It queries the database for an animal with that ID, and then it represents that animal, in this case a JSON, but you could be using a template or whatever. So, yeah, that looks simple, but we're actually not done. We haven't fulfilled our requirements. If we query an animal with an ID that does not exist, if we're querying for
a T-Rex, and it's not in our database, then we will get a 500 error, because it tries to find a T-Rex, and maybe this thing returns none, or many ORM mappers will return none, and then you try to get a title of none, and that doesn't work, and there's an exception, and the web server will make this into a 500 error.
But that's not what you want from your API, you want a 404 error. So you have to add code, you have to say, well, if there's nothing there, you have to say, okay, we're gonna return not found. Maybe you can do an exception, maybe you just return a response. So this is brand X routing with error handling. So this is more path routing.
We split the code up into two functions. If I knew I had 1900s horizontal, I would have put the first line on one line, but I thought I had much less available. So, but there's two functions. It's the same amount of lines of code if you write normal lines. You have normal line lengths, it's the same amount of code.
At least same amount of lines. So first you say there's a path to a cat or to an animal. You have to say what kind of class you're gonna return from that function first. That will be used later. And then you do the query there, and then this returns either none or an animal object, an instance of animal. And then you have a way to represent that animal. You have a view, and you say, okay, this is the default way to represent an animal.
You make its title. So you split it up like that. And, yeah, so it first goes to the model, and then a view is looked up for the model, it's a two step approach instead of a one step approach. Now, a nice benefit of this that not found actually happens automatically
because this will return none, the first function, get animal, and then the system knows, wait, we don't have an animal to represent, then four, four. So you don't have to do anything special. You just work in a normal way, you get a four, four. That's nice. And you can also have multiple named views for the same model. If you also wanna have an edit view or whatever, you can give it a name, and then animal slash cat slash edit goes to the edit view.
So this buys us, yeah, it's harder to do it wrong cuz it's easy to forget. It looks simple, but then you forget the special case. And you get better linking, so now we go on to the next topic. So let's do a little rant about linking. So links make the web work, right?
Traditional HTML websites work with links, web applications work with links. REST worked with links. I mean, there was a talk about hypermedia APIs on Tuesday, talking about how useful it is for loose coupling and scaling over multiple servers to use links and let your client follow links, just like somebody clicking on a link in a website.
So why then do Brand X web frameworks barely care about link generation? They do hardly anything. What they do is this. So you have to give your route a name so you can refer to it later. Then you have to use that name when you generate a link somehow, you know, some API, and you have to know that an ID needs to go into
the template of the URL to make the link work. So you have to know the name, introducing tight coupling between your routes and your code that uses the routes. So if you change the routes, you might have a problem. You don't want that tight coupling. I thought routes were for loose coupling, so you could change things.
And you have to know what parameters go in, and you have to extract that information from the object in order to put it in there. So, yeah, I just discussed this. This is more path linking. So there's no change to our previous code. It just is exactly the same.
And then you just have an animal object, and then you say, give me a link to it. And that works for any object that we know how to make links for. Any object that has a route declared with a path decorator will be linkable. And this is loose coupling. You can just make a link to an object without knowing what it is,
making it possible to write generic code that doesn't need to know about what kind of links you want to generate. And it's just easier. You don't have to remember all this stuff anymore. You just do it. So let's look about linking with query parameters. So imagine instead of doing what we did before, we do slash animals,
and then we have a query parameter in a URL, it's called ID, and then we give it a cat. It's very similar to the last case. And, of course, this is a bad example. It's a very simple example. That's why I put it there. A better example would be like some kind of filtering search API.
The idea of URLs is that in a good RESTful web design or a traditional HTTP website, the client does not construct any part of the URL except for the query parameters. So that's why I'm giving you this example here.
So yeah, you want to get a representation still the same. You want to get a 404 if it's not there. If you ask for the T-Rex, and if you don't supply the ID, well, the ID you want to assume some default, like, okay, the default animal is a cat, why not, right? Or you want to say, no, there is no default if you don't supply an ID
that's a bad request, and you want to get a bad request error from the system. So in brand X, you do that like this. You have to add another special case there. You have to say, okay, well, first you have to know that you have to extract this from the request, you have to do that, and then you have to say, well, if it's not there, then we have to do something special. You have to do all that extra work, and your function is getting less simple.
So, and if you were to have no default, then you want to raise a bad request. Now, Flask does automate that, actually, if you ask for something that automatically raises, and that doesn't exist in your request parameters, so it automatically raises bad requests, so that's kind of nice.
But most of them, you have to implement it yourself. In MorePath, this is the MorePath way to do that. So we've actually not changed the last three lines of the code at all. We've barely changed the top. The only thing is we've changed the URL path there to just slash animals. We've added the parameter to our getAnimal function, and we have given a default there, like Python, and that will do this for us.
So now you can just, so yeah, this is the same, so you don't need to do something special here. So now we can look at linking with query parameters. So in Brand X, in some frameworks, they have different things,
but they don't do very much. So either you sort of refer to the route name, and then you give it some keyword parameters, and those will be added to the query parameters. Or perhaps they recommend that in your template, you start adding things there that's really ugly, or you do it by hand, basically. They just sort of drop the ball on that, typically. They don't really think about query parameters very much,
because after all, they're a fundamental mechanism of how the web works. So I would think about that, right? So in Morepath, it just works like that, like before. There's no change. This link will still generate a link. It just will generate one with the cat ID in there now, if my animal happens to be a cat.
And Morepath also knows about the type of the parameter involved. So if you say this parameter needs to be an int, and often it's enough to just give the default parameter and make that be an int, the system will assume, OK, well, this should be an int. So if you then give something that cannot be converted to an int, a string as a parameter, it will try to convert it,
get a value error, and say, OK, wait, we cannot convert this 400 bad request. So it will do that for you for free. And it will do that for all kinds of parameters. You can actually plug in your own. So by default, it does dates and things like that, timestamps. So that moves on from linking. I hope I've shown you that linking can be done better.
So let's look at reuse. So Morepath offers a lot of facilities for reusing code, because when web applications grow, or you have different pieces of application you want to combine, or you have an application, and it's perfect, and it's developed by somebody else,
you just want to make a few changes, you want to do reuse, and you want to make that easy. And Morepath reuse is not like a special case. You don't have to go to a special kind of subsystem and learn all these new things. Reuse is just there as part of the system. So let's talk about view reuse first. So here we have a collection of animals
that's maybe on slash animals, you know, without the cat bit there. And we want to return some kind of JSON that has an array of animals, a list of animals, and instead of creating a list of links to animals, which we could have done with request link, we want to actually embed the information about the animal in the JSON. So we can just say, okay, give me the JSON representation,
or at least the Python representation that translates to JSON for the animal. And it doesn't care what kind of animal it is if you're getting a list of whatevers and you don't know what they are in this code. This code can be generic and still embed them or link to them. So that's view reuse. You can just reuse views,
and there's again, you have loose coupling, and you write generic code by default. And it's actually easier to write generic code by default. So here we also have a generic view. So if you have a life form base class, and you have an animal subclass that subclasses from life form, and you make a view for life form,
that view will also exist for animals. It's just inheritance basically, right? So you can make a generic view for all life forms where you say, well, for elephants, we really want to add some extra information. You can make an exception. You say, okay, well, for elephants, we have this extra thing going on here. So you can do stuff like that. And that allows you again to write generic frameworks. You can write a generic collection-based class
that then has a set of generic views, and you just have to fill in a few details. And that sort of flows from the primitives of the system. You don't have to do something else and learn new things. You can have more than one application. So a mobile application recently, actually in the most recent release, became a class. And you just have two classes here.
And then you can do all these paths and routes and stuff. You can add them to the classes. And they're independent from each other. So they don't interfere with each other. They don't share anything. So you can just have two of them. And that's actually very useful. But we'll see a little bit more of that later.
First, we're going to talk about inheritance. You can also just inherit a derived application from a base application, meaning it will share everything with the base application. So you just get that. You don't have to. It's just Python basically. But you're sharing everything, not just methods, but all these path registrations, all that stuff is also inherited. And then you can do overrides. So you can do extensions.
Let's look at the extensions first. You can say, well, the base, just inheritance is just copying as boring. You want to add something. So you can say, OK, in the derived application, everything is as the base application. When you have one extra view, it's called slash animal slash cat slash extra. And that does some extra thing for you. So you have the same application, but one extra little thing added,
which is kind of nice. You can think about framework applications that offer a sort of set of framework views that you can then reuse in multiple applications. You can do overrides. So it's still kind of like Python. So you have a base application here, and the base application has a default view for animal. But then you say, OK, well, base application is great.
All its routes, views are all great. We want to change one thing. OK, you can do that. You can say, OK, I re-register the default view for animal. Then in the derived application, that's the view you'll get. But if you use the original application that's maybe maintained by somebody else who doesn't want that override, it will still work. It will still work as before. You can do composition of applications.
So you have an application, a user application, and you have a wiki application. And they're independently developed from each other, or maybe you are developing both of them, and you don't want to think about users when you develop wikis, and you don't want to think about wikis when you develop users. So you don't want to have a URL space with users. You don't want to have to think about,
worry about users when you are developing the wiki URLs. So you just have two applications here. The one special thing we've done there is to say that the wiki application has a variable, expects to be, it's parameterized, and it's parameterized with the wiki ID. In order to create a wiki application to instantiate it, you actually have to give it the wiki ID,
otherwise it won't do anything. And they just are completely independent from each other. They just, one does a wiki, and wiki pages, and the other one does users. And now you want to combine them in each other. So you say, okay, we have the user application, and we want there to be a slash wiki on every user that has the wiki. So you say, okay, we mount the wiki application onto the user application,
and then we give it a, this is the path where we want to mount it on. So we want to mount it on wiki. And then we have to say how to get the wiki ID from the context of the user application. So we know the username, and we need to have some way to find the wiki ID for username. You look it up in some database, but that's only in the mounting code. The wiki doesn't need to care about usernames anymore.
And they, you can merge them together. You actually still have access to the username if you want to in the wiki application. So mopar has a bunch of other features I won't go into details about here. There's a built-in identity and permission system.
So you can protect views with permissions, and you can define rules for your specific system saying models of this kind, like animals. People only have the edit permission if they, you know, this table in the database says so. Whatever. You can just do whatever rules you want.
It's a very flexible system. It doesn't assume anything, so the basic core of mopar doesn't make many assumptions, but it does let you to come up with whatever rules are appropriate to your application. mopar is extensible to new view predicates. We've really only seen the name predicate where you have multiple names views. Those are get requests, but you can also make a request for the post view,
so you can have request method that's built in, but you can extend it to say, okay, this view only matches when the HTTP accept header in the request says this and this, so you can extend to that in sort of the normal, more pathway with a few decorators. It's also extensible with new converters. If your application has a specific, you know, data type, like a car or whatever,
and you have a way to represent it in URL, you can define a converter for it to just parse that and also convert it back again from a car object to a representation that you can use in your URL, either in your path or in your request parameters, and you can extend mopar itself, so you can say,
I mean, I haven't documented this, so it's sort of a special thing, but a mopar application is a bunch of generic functions. You can actually override those generic functions in your application, so if you don't like the way mopar does routing or whatever, you can actually override little bits, and it's sort of using the same mechanism to implement mopar, that mopar sort of allows you to override and extend it.
mopar does have a few extensions. I have a more.transaction extension that I sort of copied from the pyramid version of that. That basically lets you, it integrates with the transaction module, and the transaction module integrates with SQLAlchemy and ZNDB and whatever else sort of has integrates with that,
and that automatically commits when a request is handled. Unless there was an error or you're returning an explicit status code that indicates error, then it will not commit the transaction, will abort the transaction, so that's kind of a nice feature to integrate these systems in a general way, and recently I released more.static,
which is an extension that adds the ability to publish static resources like JavaScript files and CSS files in a cache-friendly way, but also in a developer-friendly way, busting the cache when you need it to the web,
and it sort of plugs in as a whiskey middleware. It's similar to fanstatic, but it's oriented around the bower tool, so you can use the bower tool to install these JavaScript libraries, and then you can just start using them without having to do any extra special work to wrap them. It's similar to fanstatic, but there you need to do the extra work.
And all this stuff is documented. Well, some of the... Extending morepath itself is not documented, but the rest of that is all documented on morepath-read-docs.org. I just checked the PDF version of the documentation, and it's about 90 pages, so I did end up writing quite a bit.
Let's look a little bit at performance, like maybe there's a huge performance cost that makes morepath very slow, but I did, I mean, it's benchmarks, right? I did a very simple hello world benchmark, and it's raw whiskey calls. There's no real whiskey server there, and morepath, it's sort of in the middle. Some systems are a lot faster, but of course, in reality,
when you look at the real web application, the overhead of actually implementing your stuff, like during the database interaction or generating views, is gonna be so much higher than the web framework. It's negligible, but I just wanted to check that morepath is not ridiculously slow, and it's faster than Flask, but a lot slower than bottle, so.
Code size, like maybe morepath is enormous. It's like, whoops, zoop, and no, it's not. I checked, and I was kind of surprised that morepath, depending on how you measure it, is smaller than bottle, though if you realize that bottle has no dependencies whatsoever, I don't know why they don't have,
yeah, I don't see the reason not to use dependencies, but morepath has a few dependencies. If you add them all up, it's about, it's gonna be smaller than Flask, definitely, or they'll call the code base. Reg is sort of the main library that morepath depends on, which is sort of a rewrite of the old zoop component architecture in terms of generic functions.
The tests, I excluded the test and the doc strings in measuring this. The tests are a lot bigger than the actual code that's being tested, which is how it should be. Yeah, we, WO is webop, and Zi is zoop.interface. I didn't list all the dependencies, and WZ is regsoic. I would have spelled it all out if I knew I had 1900 horizontal
instead of 756 or something. Conclusion. I hope that I've shown that routing and link generation and reuse in morepath is better than your brand X. Morepath tries to be,
and I hope I've shown that morepath is both easy to use. It's not much harder than Flask. It's not so intimidating. At the same time, very powerful in its reuse and overwriting potential like that, and it's also still small, so it's not intimidating in sort of what's there. And I hope I didn't make you frustrated with brand X that you may be using.
So are there any questions? Yeah, that's what happens when you wash your tiger with brand X, right?
My time, thanks for a very... If you have questions, will you go to one of the mics, please? Thanks for a very interesting talk. What is the kind of status and also the outlook or so? Is it kind of like stabilizing
and you think that the next things are going to happen with them? I mean, what are your next plans basically with that, right? There's also the question of you start to use it now. What changes do you need to adapt and it's a... So maybe a few weeks ago, I thought it was pretty stable. It was not going to change any massive way,
and then I decided to make applications classes instead of instances, which was a rather big way, though not a high burden for a developer to actually adjust any code in. I mean, that was not... So I don't think there's going to be any changes that may give you a huge problem if you start developing with it now. My plans are mostly involving writing extensions for it, like looking at some of these RESTful standards
for making links to things, building on top of more path, not growing more path itself. There's also a lot of sort of potential for writing an extension that sort of re-implements some of the pyramid authenticators to stick it based on authentication, but that's all extension. That's not core stuff. So I don't think I'm going to change it
very much anymore, but you never know when in three weeks time I have some brilliant idea. But even then, I don't think it's going to be a giant burden on whoever has a code base then. So it's getting pretty stable, I think. We are starting to use it ourselves in our own project now, so people are starting building real world in my customer project, real world code with it. So it's ready, I think, yeah.
Martin, if there are any more questions, can you take them over there and we'll get the next speaker. Okay, sure. If the next speaker can come and set up, please, and Martin will take any more questions.