Emulating Ruby's anonymous blocks with Myghty 3
Ruby’s anonymous block capability is probably the main feature I find myself wishing Python had on more than one occasion. While the upcoming Python 2.5 PEP 323 provides for the “with” statement which will enhance generators to get a bit closer. Though as Ryan Tomayko notes, this still doesn’t make the block available within the “generator”.
There are of course, many uses for having the block (with its closure scope), available in the function/generator you’re using. I’ve seen this used to easily register code call-backs with a CleanUp/Initializaiton manager, and other cases where its preferable to actually retain the block in its entirety for later execution. It’s also very useful when you want the function to control execution of the block, and return its output in a modified form.
In these ways, it would appear that the generator enhancements won’t quite be bringing the full power of Ruby anonymous blocks to Python. However, I recently found out that a relatively recent feature in my favorite Python template language, Myghty, implements something quite close to this.
Myghty’s Component Calls with Content
In a previous entry on Formencode and SQLObject I noted how useful the component call with content can be. What I failed to note (I didn’t know at the time as well), was that not only is the function/component able to get the content of the content “block”, but its also able to execute it again and again.
Consider this example from my prior entry:
Hi, lets translate the content under:
<&| MODULE:mylib:translate, lang='es' &>
This entire block of content will be sent in as a
single variable to translate.myt
for use. This includes any <b>HTML tags and such</b> as well.
</&>
and the function it calls:
from mytranslater import translated
def translate(m, lang):
body = "<p>The translated text is:</p>"
body += translated(lang, m.content())
m.write(body)
The m.content() call can be called as many times as you want the output of it, and it retains the scope of its original location. This in many ways emulates how Ruby can yield to the block and capture its output, however it is not possible to stash the block itself (in Myghty/Python).
Next up is to actually be able to use values from the function inside the block. In Ruby this is done in a very elegant fashion letting you declare what you’ll call them, then use them, like so:
SomelistOfints.each do |item|
item += 2
end
To emulate this behavior, our block has to make a special function call and know the name of the value in advance. Here’s an example:
% randomvar = 423
<&| MODULE:mylib:translate, lang='es' &>
This entire block of content will be sent in
as a single variable to translate.myt for use.
This includes any <b>HTML tags and such</b> as
well. Here's something supplied by
translate: <% m.content_args['value'] %>.
Of course, <% randomvar %> is still in scope too.
</&>
And just for fun, our translate function will call the block with some different values:
def translate(m, lang):
body = "<p>The translated and repeated text is:</p>"
for val in range(0,4):
body += m.content(value=val)
body += "<p>That's it, nothing else.</p>"
m.write(body)
The important thing to remember that makes the concept powerful is that the block above is called in the scope you saw it in the template. Whatever variables were available there are used as normal.
Close…
This method brings us close to Ruby’s anonymous blocks, as close as might be possible in Python. Unfortunately its only usable within Myghty (if not, please let me know), and its still not true anonymous blocks. At the very least, its close enough to make me happy for now. While I could just switch to Ruby entirely, there’s still way too many things about Python that I’d miss.
From the details of PEP 343, it appears that this full capability to pass the block in was purposely avoided as having flow control in the “macro” makes the code inscrutable. Hopefully someday the utility and power such functionality provides will result in it being available in Python. Or at the very least, some clever person can try a variant in PyPy and see what sticks.
And yes, I know nested functions can be used and passed around with their closure, but its pretty annoying to be nesting functions back and forth solely for that purpose. It feels like all we have is a hammer…
Further reference:
Is Rails a DSL? What is a DSL, and is it possible in Python? 9
I keep seeing blogs and blog comments pop up with some very odd notions. Many of these are summed up in this comment from a recent post by Tim on Ruby books
“It’s doubtful that the Python folks can come up with anything as compelling (or elegant) as Rails. Why? Because Ruby is so good at creating Domain Specific Langauges (DSLs). Ruby’s anonymous code blocks are a big part of what enables DSLs to be written so easily in the language. Python doesn’t have them. Python’s lambda’s (and closures in general) are crippled as well, which also doesn’t help Python’s cause.”
What is a Domain Specific Language (DSL)?
I always like to carefully define my terms before actually talking about them. So first I looked up several common definitions of a DSL. We have Martin Fowler’s entry on a DSL which describes it as:
“The basic idea of a domain specific language (DSL) is a computer language that’s targeted to a particular kind of problem, rather than a general purpose language that’s aimed at any kind of software problem.”
He further clarifies between two types of DSL:
“The most common unix-style approach is to define a language syntax and then either use code generation to a general purpose language, or write an interpreter for the DSL. Unix has many tools that make this easier. I use the term External DSL to refer to this kind of DSL.”
“The lisp and smalltalk communities also have a strong tradition of DSLs, but they tend to do it another way. Rather than define a new language, they morph the general purpose language into the DSL. (Paul Graham describes this well in Programming Bottom-Up.) This Internal DSL (also referred to as an embedded DSL) uses the constructs of the programming language itself to define to DSL.”
To summarize, an Internal DSL satisfies one of the following:
- Uses a general purpose language, then morphs it into a language to fit the domain
- Adds functionality to a general purpose language such that solving a specific domains problem is easier
An External DSL:
- Completely new language syntax
- Typically requires code generation or interpreter for DSL
Martin Fowler espouses on how very dynamic languages like Lisp, Smalltalk, and Ruby are more conducive to internal DSLs as the meta programming capabilities and dynamic nature make it easy to extend and customize the functionality for your domain. I completely agree with his contention that an Internal DSL is limited by the syntax and structure of the language.
DSL’s in Python and Ruby
While the anonymous code blocks in Ruby are useful and syntactically nice, similar functionality can be done in Python through the use of generators and iterators (more powerful generator functionality similar to Ruby’s anonymous blocks are planned for Python 2.5).
Ruby also lets you extend built-in types, which is utilized by Rails to add a few helper functions to core Ruby data types. Python and Ruby both have closures that operate slightly differently, Ruby’s closure is definitely more “full featured”. However this typically isn’t a problem because of list comprehension’s, generator expressions, and generators/iterators.
Zope is a very clear example that its quite possible to build an internal DSL in Python. Whether they built it in a clear, easy to use way is up for someone else to debate. SQLObject makes dealing with databases as easy as ActiveRecord, and there’s many other examples of internal DSL’s built in Python (Take a look at twill, a web application testing language implemented in Python).
Is Rails a DSL?
First, it should be obvious that if Rails is a DSL, its an Internal DSL. The most noticeable strides towards being a web programming DSL in Rails:
- Over a dozen core Ruby classes are extended/modified
- Dozens of helper functions
- New classes (syntactic sugar) defining database access and web paradigms
Given how loose the definition of internal DSL is, I think its clear that Rails qualifies, so does Django, TurboGears, Aquarium, etc.
If you prefer to be more strict about an internet DSL, and argue that a lay programmer needs to be able to do a reasonable amount of ‘work’ without knowing the base language implementing it, Rails starts to move apart. You can do a reasonably large amount of work in Rails without knowing Ruby. A lot can also be done in Zope without knowing Python.
In either case, you can’t really start to make advanced applications in any of the frameworks without knowing the general purpose language its built on. DSL’s can and have been built in Python, and I believe if you go out and start counting them up, you’ll see more DSL’s implemented in Python than in Ruby.
Anyways, hopefully for people that run around re-iterating something they heard somewhere about DSL’s and Python vs. Ruby, this clarified something. It’s easy to create DSL’s in Python, lots of people do, and there’s lots of them. Python and Ruby are both great for making them, outside of Rails I don’t know any other DSL’s in Ruby. Perhaps someone can compile a list of all the internal DSL’s written in both Ruby and Python?
The Wacky World of Ruby 9
Ruby is a fairly interesting programming language, from the “expressive” syntax to some of the absolutely bizarre documentation. For a Python programmer, the lack of predictability and almost excessively concise syntax (when just one more line would really make things a lot clearer) can be a bit of a downer. Overall though, I’m rather enjoying my experiences with Ruby but not enough that I’d want to use it exclusively.
The “Wacky” bit I cite, comes from some of the strange directions the language seems to go and wacky documentation and books available. Now, the creator of Ruby is completely aware about some of the ways in which Ruby sucks as he put it, and 3 of those are of particular importance to Python programmers since we enjoy a concise (and not complex), predictable, and consistent language. Ruby is working to address these issues in the upcoming 2.0 release which I’m hoping will make it more pleasant to work with.
It is also somewhat wacky the way the Ruby community has compared themselves to other programming language communities to which this blogger has a fairly friendly reply. Sometimes these little jabs run into the printed documentation regarding Ruby as well, which is a big turn-off for me, especially since I really disagree with the reasons that are cited for insulting other languages.
Beyond Java?
Take the Beyond Java book for example. About half-way in it becomes very clear that the author’s view of what is Beyond Java…. is Ruby, and for web programming, Ruby on Rails. The author then goes on to smash Perl, Python, and PHP (ok, I agree with him on PHP :). He puts Ruby in the mix as well, but the only bad thing he says about it is that its lacking commercial backing (except for later on where a new reason emerges).
His comments regarding Python are truly wacky though, as he jumps back to the very old “white-space reliance sucks” argument that hardly ever comes up in the real world. I’ve been using Python for over a year now, and have worked on quite a few collaborative projects, and have yet to see a single error related to mismatched white-space. This is probably because coding standards are well known and Python programmers actually follow them for the most part. It’s hard to express how wonderful this has made it when I’ve jumped into code written by other people, and have been able to easily scan it and add functionality after just a few minutes of looking it over.
When I’ve jumped into other people’s Ruby code looking to make a quick-fix, the syntax quickly became a massive chore to decipher as Perl’s motto of TMTOWTDI holds very true in Ruby as well.
The Beyond Java book also cites Python’s lack of a “killer app” when it comes to web programming and specifically references Ian Bicking’s article on web programming frameworks. Of course, since that article Ian has put out Python Paste which solves a host of problems he mentioned there, and the Python web community’s move to WSGI is helping to standardize methods of running Python web applications.
Even more wacky, later in the Beyond Java book, in yet another comparison of whats for and against the languages, a different reason pops up for Ruby not doing so good. What is it this time?
The biggest strike against Ruby right now is the lack of a strong project that lets Ruby run on the JVM. – Page 163
He goes on to cite how much support Ruby would get if Microsoft was able to woo the Ruby founders over to .NET’s CLR. On the very next page (165) another for and against argument comes out for Python. Since the author just mentioned the JVM and .Net CLR as major drawbacks to Ruby, I was actually expecting him to mention Jython, or even IronPython which is actually being developed by a programmer now at Microsoft. Amazingly enough, neither of these projects is mentioned here, though Jython was mentioned back near the beginning as being too slow (which IronPython apparently solves).
It gets even more wacky a few more pages in, as his reasons against Perl come out.
Perl does have a downside. When you look at overall productivity of a language, you’ve also got to take things like maintenance and readability into account. Perl tends to rate very poorly among experts on a readability scale. - Page 174
Who these experts are is never mentioned, and I’ve seen “experts” for and against the Perl syntax. While Ruby is easier to read than Perl in my personal opinion, its nowhere near as easy to read as Python.
Programming Ruby, The Pragmatic Programmers Guide
I’ve been reading this book for awhile now, and the author’s decision to do something different is admirable but has really been a bane to reading the book. I’ve also read the Agile Web Development with Rails book, which I think was done in a most excellent manner (written by Dave Thomas, the author of Programming Ruby). So this isn’t an attack on Dave, as I really enjoy his writing, I just believe this approach didn’t work so well.
The approach taken in Programming Ruby is to breeze over high-level uses of the language without actually explaining much about why things acted as they do. This quickly drove me nuts, and I stopped reading the entire intro as seeing syntax for no reason wasn’t helping me learn anything. If you want to learn Ruby in the way most programming books teach a language, by carefully and completely going over all the parts then doing more advanced things; skip to page 317 in the Ruby Crystallized Part.
Once I started reading here, everything fell into place very nicely and the language really started to make sense. If the sections were reversed as most programming books have it, I’d consider this book pretty much perfect for a programming book. The thing I think Dave might have missed here, is that most programming books follow this convention because it works. Being different, just to be different, isn’t very good unless there’s a real and practical reason for doing it.
The wackiness doesn’t end though, and I have yet to complete the entire book so I can’t say how many more examples of this are there. Here’s the latest gem though, which actually prompted this entry (though I’ve been thinking these thoughts for awhile).
On Page 330, going over the details of Variables and Constants, I came across this:
Ruby, unlike less flexible languages, lets you alter the value of a constant, although this will generate a warning message.
HUH? Errr, then why the heck do they call it a Constant?? Seriously, maybe its because I’m picky on language terms used but I think they should’ve called it a semi-Constant, or a mostly-Constant Constant. For me, this goes against the entire notion of what a Constant is. Then, on top of that, it insults other “less flexible languages” that (gasp) don’t let you change constants.
It’s a Wacky World
There’s many more examples of the wackiness present in the Ruby world. Perhaps its because the language is from Japan, home to so many wacky things by Western standards. Though the writers I mentioned are all non-Japanese, so this explanation doesn’t really cut it. To be fair, the Beyond Java book is well written and the reasons cited in many of the comparisons are valid to an extent.
Ruby in Rails also has its share of wackiness, though it seems so abundant I’ll have to save that for another post entirely. If you’re wondering after all this, why I’m still using Ruby… well, it’s a wacky world, and I do kind of like wacky (I think I’ve used up all allowed uses of the word ‘wacky’ by now). Ruby 2.0 looks to be quite appealing and it’ll be interesting to see how Rails adapts to so many breakage’s that 2.0 appears to introduce over 1.8.
Python isn’t perfect either, and I’m not going to claim it is. There’s plenty of people in both the Python world and the Ruby world who are very forthcoming about failures and successes of the language, so the views expressed by the authors in these books should not be taken to represent the whole. They are some of the most visible speakers though, so I hope that they can someday be as forthcoming as Matz has been.
Best of breed Controllers for MVC web frameworks 19
I’ve been doing a lot of comparisons and research into various Python web frameworks lately, mainly focused on MVC oriented frameworks. Some of them have templating languages they come with, some not so much. The thing I have started to notice is how similar the Controller in them all is starting to look. First though, lets see what they all can do when it comes to the Controller.
For comparison’s sake, I’m bringing out some examples using CherryPy, Myghty, Bricks, Aquarium, Ruby on Rails, and Django.
Please note I’m not including frameworks built using any of the ones mentioned as their Controller looks pretty much the same. I’m also not an expert in all these frameworks as I only have so much time in the day, so if I seem vague on something its because I don’t know for sure. Feel free to comment (or correct) and clear up any vagueness I express.
Dispatch and Responder Styles
All the frameworks I’ve mentioned implement a style of object publishing (sometimes referred to as dispatch-style) that maps to the URL coming in. If you have another name you want to call this, go for it, I haven’t seen anything consistent on what to call this stuff.
Three different styles seem to exist that make sure an object responds to the URL:- User creates a regular expression to explicitly map a URL to an object (Explicit Mapping)
(r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.apps.polls.views.polls.vote')(from Django tutorial)
- Object is mapped out according to the URL (Implicit Mapping)
- /admin/login/hello/—> admin/login.py/hello() (Myghty)
- Programmatic rule set determines object that responds (Programmatic Mapping)
- map.connect ’:controller/:action/:id’ (Rails)
- m.connect(’:controller/:action/:id’) (Routes)
- Create a class inheriting from a Controller object, methods of the class instance are called to respond (Class-method)
- Create a callable object that responds (Callable)
- Create a function thats directly called (Function)
Note that the last 2 are functionally equivalent for the most part, however a callable object has the typical advantages (or disadvantages) of persistence in some web frameworks, as such if a web framework only shows one of those styles I won’t mention the other. Curious what frameworks use what styles from the above two sets?
For this listing, I’ll refer to the mapping scenario as dispatch-style and the method for defining the response as the responder-style, also please note that some frameworks support multiple dispatch-styles and responder-styles.
Aquarium:- Dispatch-Style Mapping 1^:
- Explicit, Implicit, Programmatic
- Responder-Styles:
- Callable (Though it looks almost exactly like the Class-method style)
- Dispatch-Style Mapping:
- Implicit
- Responder-Styles:
- Class-method
- Dispatch-Style Mapping:
- Explicit (Not with regexp’s though, each class is attached off the root to determine what URL leads to it)
- Responder-Styles:
- Class-method (Must be explicitly exposed with @cpg.expose)
- Dispatch-Style Mapping:
- Explicit
- Responder-Styles:
- Function (Packaged in the same module if they’re related)
- Dispatch-Style Mapping ^1:
- Explicit, Implicit, (Programmatic with Routes in upcoming 0.99)
- Responder-Styles:
- Class-method, Callable, Function
- Dispatch-Style Mapping 1^:
- Programmatic
- Responder-Styles:
- Class-method
1^: User can create custom dispatchers to determine responder object
Who did it first?
If we throw in two more frameworks that utilize CherryPy, like Subway, and TurboGear, we can start to see that using a responder-style of Class-method is pretty popular. What’s even more interesting is that all the Class-method Controllers look remarkably similar, and I don’t think its because they’re copying each other.
The Aquarium project appears to be approximately 4 years old now, but from looking at the mailing list had little or no users until only 2-3 years ago (One poster from 2001 describes his aquarium plants turning brown…). From the sourceforge changelogs, the Controller stuff was added with 1.4 release in 2004. CherryPy has been around for 3+ years and I’m presuming it had the Controller stuff in it from the get-go as it seems a pretty core function of CherryPy. Rails has been out for a year or so, and was used in a form internally for BaseCamp for awhile predating that.
If you really want to trace back this style of Controller, you’d most likely find yourself looking at Java Python code (See Phillip J. Eby’s comment below). I’m really just trying to point out here, that even if one of these projects saw something they liked from the other, none of them were the originators. They all took a good concept, and implemented it differently, though they’ve all started to look remarkably similar.
A Controller Line-Up
So lets take a look at some of the examples on the pages of each respective website. Django is the only one that really stands out, as they’re not using a Class to contain the methods, rather they’re grouping them as plain functions inside a module.
Aquarium
class BaseController(Controller):
def __call__(self, callNext, *args, **kargs):
"""Save a reference to myself in ctx.controller."""
self._ctx.controller = self
callNext(*args, **kargs)
def doMessageAddAction(self):
"""Add a new message.
...does a bunch of stuff...
I mentioned that it was Callable but functioned in a way like a Class-method. This appears to be because Aquarium puts a context and maybe other initialization stuff per request in the __call__ bit, then has it actually calls a different method to respond.
Bricks
from bricks.controller.crud import CRUD
from bricks import user
class Test(CRUD):
# Override the default delete() method
def delete(self, rowid):
return CRUD.delete(self, rowid)
delete.expose = user(level=1, app='app')
controller = Test('todo')
Bricks adds an interesting ability here by attaching function attributes to indicate what authorization is needed to execute the function called. Some of the other frameworks shown here do similar things through function decorators.
CherryPy
from cherrypy import cpg
class HelloWorld:
def index(self):
return "Hello world!"
index.exposed = True
cpg.root = HelloWorld()
Notice that the class instance is attached to the location off cpg.root thats desired. To map a URL to a class instance farther down, say under /booga instead of /, you’d do that last line like so:
cpg.root.booga = HelloWorld()
Pretty handy I think, and it beats writing regular expressions (though doesn’t appear as flexible). One of the reasons I prefer the Programmatic dispatch-style. Moving on..
Django
from django.core.extensions import get_object_or_404, render_to_response
from django.models.polls import choices, polls
from django.utils.httpwrappers import HttpResponseRedirect
def vote(request, poll_id):
p = get_object_or_404(polls, pk=poll_id)
... does a bunch more stuff to use Django-supplied functionality...
If you imagined the functions inside a class, instead of a module, it’d look rather similar to the others….
Myghty
class HelloWorld:
def doit(self, m, **params):
m.write("hello world!")
helloworld = HelloWorld()
At this point, the similarity between Bricks, CherryPy, and Myghty should be pretty obvious. Aquarium is close as well, while Django is only a wee farther from what’s appearing to be the norm.
Rails
class HelloController < ApplicationController
def index
return render :text => "hello world!"
end
end
Doesn’t look too different from some of our Python MVC frameworks…
What it All Means
I have no idea. Really, I just thought it was fascinating that these different frameworks started looking so similar. Some of them have been incredibly similar before others, but obviously these approaches catch on and find themselves adopted into other frameworks.
I do start to wonder at what point they’ll be similar enough that the barrier to switching web frameworks is narrowed down to only a few dozen lines of code to change here and there. Sure, going to/from Rails is going to be tough as that also means a language change, but for Python programmers tempted by a feature a different web framework offers I won’t be surprised to see more people hopping back and forth.
With regard to the Python web frameworks, none of them appear to agree on a template language. Several of them use Cheetah, some use Myghty’s template abilities, one uses Kid, and several of them have their very own template language.
It’s also interesting to consider whether or not having more possible dispatch/responder styles is beneficial or detrimental to the popularity of a specific framework. Rails creator David Hansson purposely includes only one style for each as he emphasizes with a concept known as convention over configuration. He provides defaults for pretty much everything, and following conventions makes it easier to write code as it enforces a consistent programming and naming style. I can’t help but notice that of the frameworks I mentioned above, the ones with less (apparent) options and better defaults tend to have more users (With the exception of Bricks as its still in alpha).
You might have noticed I designated Rails as being capable of user-programmed dispatching. While Rails uses its routes system by default, the thing people miss is that they’re just defaults. You can get in there and totally alter the way it works if you want, Ruby doesn’t completely close classes so you could just re-open them and override any aspect of its dispatch system you like.
I think this a valuable lesson that some of the more “verbose” examples above might want to consider. If there’s lines of code in a controller that you have to put in there every-time, find a way to make it the default case so that boiler-plate isn’t needed. It only needs to be a default, an advanced programmer will know how to override it should they need to. There’s obvious limitations to this since things work differently in Python, but there’s still Python ways to do it in a way that feels “right”.
For the Python Web Frameworks I missed
I know, I didn’t cover SkunkWeb, Spyce, Snaklets, Webware and more. Please feel free to add the relevant information regarding your framework in the comments. It’d be helpful if you could indicate what Dispatch-Styles and -Responder-Styles your framework supports.
If I failed to properly cover one of the above frameworks, bringing that to my attention is most appreciated.
The comment system supports the Textile format.
Where's Single Sign-On? Part 2 7
In a recent Wired article regarding One Login, reference is made to a new social style network called GoingOn. The article spends most of its time focusing on one site that hopes to aggregate functionality that currently is split between Blogger, Flickr, Friendster, and Bloglines (for the most part). However, the thing it misses is what I previously discussed regarding the lack of a working distributed identity system.
After looking around more, I’m happy to say there are indeed working identity systems out there. Unfortunately the most promised of them, the Liberty Alliance doesn’t seem to have much oomph behind it, but two others that I previously didn’t know about are now out there.
The first is from the folks at Microsoft, which they’ve called an Identity Meta-System (or something like that), which is described over at vnunet. It seems to be rather tied (or at least integrated heavily) to Microsoft technology (go figure!), and will be included in Indigo and other various Micrsoft technologies. As a mainly open-source coder, this has little appeal to me, nor am I about to start using Microsoft API’s to write my websites and web code. The standards utilized by Microsoft for their Federated Identity are generally known as WS-* for some reason I’m too lazy to investigate.
The second is much more appealing (to interested users and web developers), and has actually been around for a very long time in a primitive form (2000 is ancient by web standards). The home site appears to be the identity commons, and the current sole Identity Broker is 2idi, the organization behind the standards is XDI. They’ve made the entire code-base they run the Identity Broker on, open-source under the Affero General Public License to ensure that users are never locked into just one Identity Broker (Yea!).
If you’re curious how the Microsoft and Liberty Alliance methodology differs, idcommons has a useful FAQ addressing the differences.
The most exciting aspect for me, is that all the technology behind the XDI approach is completely open-source, and geared towards maximum user flexibility and empowerment. The user gets to move data between Identity Brokers, and every care has been made to ensure the user is never locked into a single Identity Broker. Actually, the most exciting part, is that it works right now. :)
They’re currently preparing to switch to a SAML-2.0 backed code-base, however the code they have only works from PHP, Java, and Perl. If you want to try it out, here’s how to get an i-Name, and you can try it out on those two sites. Also, a developer made a ISSO (I-name Single Sign-On) authentication system for WordPress which is pretty cool.
So what’s stopping ISSO from being used on more websites? It’s free, its open-source, its standards based, its not controlled by a commercial corporation….
It needs Python libraries!
I should mention, when I first wrote this as far as I knew, there was no Ruby version. There still isn’t a public one, but Victor Grey is fairly close to a Ruby version with a full Rails rig to go with it which I’m rather looking forward to.
Anyone want to help? I’m tired of remembering a zillion usernames and passwords, and with ISSO on the horizon I shouldn’t need to, all the Python web frameworks will be a bit better (at least the sites that use usernames/passwords) with an easy way to use ISSO.
By the way, for a useful overview of SAML, there’s a very detailed write-up of SAML2 on xml.com.
Older posts: 1 2





