-
Notifications
You must be signed in to change notification settings - Fork 17
/
CHANGES.txt
880 lines (621 loc) · 29.9 KB
/
CHANGES.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
Version 1.0b1 - April 03, 2011
==============================
*This change log is a work in progress*
Tipfy 0.7 is a huge step with several additional features and improvements in
tipfy's core design. Here's an overview of what is new:
- NEW: Tipfy can now be used outside of App Engine. Variables that are not
thread safe are now stored in thread locals.
- NEW: a `current_handler` global is available in tipfy, providing access to
the currently matched RequestHandler. The handler becomes a central piece
to access the WSGI app, request and the utilities it provides such as lazily
loaded auth, i18n and sessions.
- NEW: tipfy.utils provides the functions json_decode and json_encode, which
will use the best simplejson module available and apply correct escaping.
- NEW: added a simple template engine (from Tornado), mainly to remove
debugger dependency from Jinja2.
- NEW: KeyProperty model was added to the db extension. [explain]
- NEW: ETagMiddleware. [explain]
- REMOVED: 3 configuration keys. [explain]
- NEW added 4 App Engine related flags to Tipfy:
- DEV_APPSERVER: True is the app is using the dev server, False otherwise.
- APPENGINE: True is the app is running on App Engine, False otherwise.
- APPLICATION_ID: the application ID as defined in *app.yaml*.
- CURRENT_VERSION_ID: the deployed version ID. Always '1' when using
the dev server.
- NEW: auth, debugger, i18n and sessions are now part of tipfy core. They are
all optional, lazily loaded, default and overridable implementations.
Auth
----
- NEW: Auth is now part of tipfy core. The auth store is configured in tipfy
module and uses an App Engine store by default::
config['tipfy'] = {
'auth_store_class': 'tipfy.appengine.auth.AuthStore',
}
Then it is available through lazy loading in the RequestHandler:
- RequestHandler.auth provides access to the configured auth store.
Example::
class MyHandler(RequestHandler):
def get(self, **kwargs):
# Get the current user, if any.
current_user = self.auth.user
# Generate a login URL.
login_url = self.auth.login_url()
- NEW: AppEngineMixedAuthStore, which allows login using App Engine Auth
across subdomains. It mixes App Engine auth with own sessions to achieve
this.
- NEW: UserRequiredIfAuthenticatedMiddleware and user_required_if_authenticated
decorator. They allow non-logged in users to access a page, but require an
user to be created if they are logged in.
I18n
----
- NEW: i18n is now part of tipfy core. The i18n store is configured in
tipfy module and uses the shipped store by default::
config['tipfy'] = {
'i18n_store_class': 'tipfy.i18n.I18nStore',
}
Then it is available through lazy loading in the RequestHandler:
- RequestHandler.i18n provides access to the configured i18n store.
Example::
class MyHandler(RequestHandler):
def get(self, **kwargs):
# Get a translated string.
message = self.i18n.gettext('Translate me')
Global i18n functions are still available in tipfy.i18n.
Sessions
--------
- NEW: Sessions are now part of tipfy core. The auth store is configured in
tipfy module and uses the shipped store by default::
config['tipfy'] = {
'session_store_class': 'tipfy.sessions.SessionStore',
}
Then it is available through lazy loading in the RequestHandler:
- RequestHandler.session provides access to the session using the configured
backend and session key.
- RequestHandler.session_store provides session related utilities such as
getting sessions from different backends and setting/deleting cookies.
Example::
class MyHandler(RequestHandler):
middleware = [SessionMiddleware()]
def get(self, **kwargs):
# Set a value in the current session.
self.session['foo'] = 'bar'
# Get a list of flash messages.
flashes = self.session.get_flashes()
# Add a flash message.
self.session.flash('Hello, world!')
# Get a session from a different backend.
session = self.session_store.get_session(backend='memcache')
- NEW: secure cookie has a faster and easier to use implementation. See
tipfy.sessions.SecureCookieStore.
- NEW: flash messages now have a category and configurable key [explain]
Debugger
--------
- NEW: Debugger is now part of tipfy core, without extra-dependencies.
Previously the debugger was dependent on Jinja2, but now it uses the built-in
template engine. The debugger is enabled by default when in development mode,
and can be disabled with a configuration:
config['tipfy'] = {
'enable_debugger': False,
}
- IMPROVED: the debugger now works even if the libraries are imported using
zipimport.
Routing
-------
- NEW: rules can define the method that will be called from the handler. The
method is defined using a 'Handler:method' notation in the Rule
definition. Example:
# handlers.py
class MyHandler(RequestHandler):
def my_method(self, **kwargs):
return Response('I am not coming from a get() method!')
# main.py
app = Tipfy(rules=[
Rule('/', name='home', handler='handlers.MyHandler:my_method')
])
This opens a whole new set of possibilities for routing and handler
definitions, as you can match the HTTP method scheme and custom method
scheme for the same handler, requiring less class definitions. For example,
a single class can handle listing, viewing, inserting, editting and
deleting::
rules = [
HandlerPrefix('handlers.ImageHandler', [
# List images is handled by ImageHandler.index()
Rule('/images/', name='images/index', handler=':index'),
# Adding an image is handled by ImageHandler.new()
Rule('/images/new', name='images/edit', handler=':new'),
# Displaying an image is handled by ImageHandler.get()
Rule('/image/<key>', name='images/view', handler=''),
# Editting an image is handled by ImageHandler.edit()
Rule('/images/<key>/edit', name='images/edit', handler=':edit'),
# Deleting an image is handled by ImageHandler.delete()
Rule('/images/<key>/delete', name='images/delete', handler=':delete'),
],
]
- NEW: added a router object that centralizes URL matching, dispatching and
building URLs. It makes it more flexible to implement alternative routing
schemes. Some implications:
- Moved methods from Tipfy that are now part of the router functionality:
get_url_map(), add_url_rule(), match_url(), pre_dispatch(), dispatch() and
post_dispatch(). If you extended them in some way, you must now extend
the router.
- URL building is centralized in the router, so url_for() methods
(from RequestHandler or Tipfy) call router.build().
- NEW: added a new rule converter, RegexConverter, which can be usefull
specially to match subdomains excluding some default ones (e.g., 'www').
For example, here we define a rule for the root URL of all non-www
subdomains, and a different one for www::
rules = [
Rule('/', endpoint='index', handler='IndexHandler'),
Subdomain(r'<regex("(?!www\\b)\\w+"):namespace>', [
Rule('/', endpoint='index', handler='SubdomainIndexHandler'),
]),
]
In this example, the request method is ignored since the Rule defines which
handler method will handle all requests.
- IMPROVED: url_for() has a few more keywords with special meanings, all
prefixed with underscore. This is the full list of special keywords:
- **_full**: If True, builds an absolute URL.
- **_method**: Uses a rule defined to handle specific request
methods, if any are defined.
- **_scheme**: URL scheme, e.g., `http` or `https`. If defined,
an absolute URL is always returned.
- **_netloc**: Network location, e.g., `www.google.com`. If
defined, an absolute URL is always returned.
- **_anchor**: If set, appends an anchor to generated URL.
- IMPROVED: Rule now accepts 'name' as keyword argument. It is an alias to
'endpoint'. This is just for semantic correctness in tipfy context and
'endpoint' will still work::
Rule('/', name='home', handler='handlers.HomeHandler')
# is the same as...
Rule('/', endpoint='home', handler='handlers.HomeHandler')
- CHANGED: URL rules are not automatically loaded from urls.py. Instead tipfy
is instantiated passing the URL rules, like webapp. Later other rules can
be added to the router. For example:
app = Tipfy(rules=[
Rule('/', name='home', handler='handlers.HomeHandler'),
Rule('/about', name='about', handler='handlers.AboutHandler'),
])
# Add an extra rule.
app.router.add(Rule('/contact', name='contact', handler='handlers.ContactHandler'))
# Or add a list of rules.
app.router.add([
Rule('/products', name='products', handler='handlers.ProductsHandler'),
Rule('/history', name='history', handler='handlers.HistorytHandler'),
])
The previous behavior using urls.py is easy to reproduce. For example,
given a urls.py like the following:
from tipfy import Rule
def get_rules(app):
rules = [
Rule('/', name='home', handler='handlers.HomeHandler'),
Rule('/about', name='about', handler='handlers.AboutHandler'),
Rule('/contact', name='contact', handler='handlers.ContactHandler'),
]
return rules
You can still import and use it in main.py:
from urls import get_rules
app = Tipfy()
# Add a list of rules.
app.router.add(get_rules(app))
Or you can simply have a list of rules defined in urls.py, outside of a
function, and import it:
from urls import rules
app = Tipfy(rules=rules)
- IMPROVED: redirect() (or self.redirect() in handlers) now accepts relative
URLs. If a relative URL is passed, it'll be joined to the current request
URL. This is mostly useful to redirect to the result of url_for() without
needing to build a full URL::
# current URL is http://localhost/foo/bar
# redirects to http://localhost/baz
return redirect('/baz')
...but it also allows curious results for relative paths:
# current URL is http://localhost/foo/bar
# redirects to http://localhost/foo/baz
return redirect('./baz')
# redirects to http://localhost/baz
return redirect('../baz')
Config
------
- IMPROVED: configuration now behaves exactly like a dictionary, still
auto-loading configuration values when needed and honoring required configs.
For example, we always used this::
secret_key = self.app.get_config('tipfy.sessions', 'secret_key')
Now it is also possible to use direct access and dict methods::
secret_key = self.app.config['tipfy.sessions']['secret_key']
# or...
secret_key = self.app.config['tipfy.sessions'].get('secret_key')
# or...
secret_key = self.app.config.get('tipfy.sessions').get('secret_key')
The previous get_config() method works as always.
WSGI App
--------
- NEW: Added Tipfy.make_response(). With this, handler methods are not
required to always return a response. If a string or unicode is returned,
it is converted to a response. Other possibility is to return a tuple to
build a response. HTTPExceptions are also converted to a proper response
when returned. Example:
class MyHandler(RequestHandler):
def get(self, **kwargs):
# Returns a simple string.
return 'Hello, World'
# Returns a tuple of values to create a response.
return 'Not Found', 404
# Return an HTTPException which will be converted to a response.
return MethodNotAllowed()
- NEW: added Tipfy.get_test_handler(). This provides a context to test a
handler, matching it from a custom request if needed. This is intended to be
used with a `with` statement::
from __future__ import with_statement
from tipfy import Tipfy, Rule
app = Tipfy(rules=[
Rule('/about', name='home', handler='handlers.AboutHandler'),
])
with app.get_test_handler('/about') as handler:
self.assertEqual(handler.url_for('/', _full=True),
'http://localhost/about')
- NEW: app has now a debug attribute, set when it is initialized with
debug=True.
- IMPROVED: Exception handling [explain]
- REMOVED: make_wsgi_app() and run_wsgi_app(). [explain]
- CHANGED: removed ALLOWED_METHODS, and Tipfy has now an ``allowed_methods``
attribute. This makes it easier to enable extra methods (say, for WebDAV)
for an app instance or extended app.
Request
-------
- NEW: Request can now automatically decode JSON requests. If the request
mimetype is 'application/json', the decoded request data is available in
request.json.
Buildout
--------
- IMPROVED: simplified buildout project structure to remove cruft:
- 'etc/' is removed and its contents go to 'var/'.
- 'distlib/' is now placed in 'lib/dist/'.
Jinja2
------
- tipfyext.jinja2 allows to set custom extensions, globals and filters more
easily. [explain]
- ...
Version 0.6.3 - August 24, 2010
===============================
- Updated zc.buildout 1.5.0 was causing problems, so now we force 1.4.4 in
bootstrap.py.
Version 0.6.2 - August 20, 2010
===============================
- Added Tipfy.run(): run_wsgi_app(app) is now deprecated and calls app.run().
Version 0.6.1 - August 19, 2010
===============================
- RequestHandler instances are now callables. __call__() is used instead of
dispatch(), which is now deprecated and just calls the instance.
- Added RequestHandler methods:
- abort(), a wrapper for abort().
- get_config(), a wrapper for Config.get_or_load().
- handle_exception()
- redirect().
- redirect_to(): redirect() + url_for()
- url_for():
- Added get_valid_methods(), which returns the HTTP methods a handler can
handle. This is used when raising MethodNotAllowed, which now correctly
lists the allowed methods as required by HTTP 1.1 spec.
- Added HandlerPrefix, a rule factory to prefix handler definition in rules.
For example, take these rules::
rules = [
HandlerPrefix('my_app.handlers.', [
Rule('/', endpoint='index', handler='IndexHandler'),
Rule('/entry/<entry_slug>', endpoint='show', handler='ShowHandler'),
]),
]
These are the same as::
rules = [
Rule('/', endpoint='index', handler='my_app.handlers.IndexHandler'),
Rule('/entry/<entry_slug>', endpoint='show', handler='my_app.handlers.ShowHandler'),
]
- If the requested method is not in ALLOWED_METHODS, a NotImplemented exception
("501 Not Implemented") is raised, instead of MethodNotAllowed ("405 Method
Not Allowed").
- ALLOWED_METHODS are now listed in upper case.
- Moved the logic from Tipfy.get_config() to the new method
Config.get_or_load().
- REMOVED: app_id argument from Tipfy.__init__(). Not really needed or used.
- Exceptions caused when importing a badly configured middleware class are now
caught and a warning is emitted.
Version 0.6 - July 25, 2010
===========================
- Handler definitions in URL rules can now also be a RequestHandler class,
instead of a string.
- Added support for single-file apps, much like we see in webapp. Tipfy can
now be instantiated passing a list of URL rules, so apps can be entirely
defined in a single file mapped in app.yaml, without the need for a separate
urls.py::
import sys
sys.path.insert(0, 'distlib')
from tipfy import RequestHandler, Rule, make_wsgi_app, run_wsgi_app
class HelloWorldHandler(RequestHandler):
def get(self, **kwargs):
return 'Hello, World!'
class ByeWorldHandler(RequestHandler):
def get(self, **kwargs):
return 'Bye, World!'
app = make_wsgi_app(rules=[
Rule('/', endpoint='hello', handler=HelloWorldHandler),
Rule('/bye', endpoint='bye', handler=ByeWorldHandler),
])
def main():
run_wsgi_app(app)
if __name__ == '__main__':
main()
This also helps to test handlers defined in a test file::
import unittest
from tipfy import RequestHandler, Rule, Tipfy, redirect
class TestHandler(unittest.TestCase):
def test_redirect(self):
class Handler1(RequestHandler):
def get(self, **kwargs):
return redirect_to('test2')
class Handler2(RequestHandler):
def get(self, **kwargs):
return 'Hello, World!'
rules = [
Rule('/1', endpoint='test1', handler=Handler1),
Rule('/2', endpoint='test2', handler=Handler2),
]
app = Tipfy(rules=rules)
client = app.get_test_client()
response = client.get('/1', follow_redirects=True)
assert response.data == 'Hello, World!'
- Added get_url_map() and add_url_rule() methods to the WSGI app.
- The returned value from a RequestHandler is converted to a proper Response
object if needed. So a simple string can also be returned, among other
options::
from tipfy import RequestHandler, Response
class HelloWorldHandler(RequestHandler):
def get(self):
return 'Hello, World!'
Backwards compatibility warnings
--------------------------------
- REMOVED: 'url_rules', 'url_map' and 'url_map_kwargs' config keys, now
redundant with the possibility to override get_url_map() or instantiate
the WSGI app passing URL rules.
- REMOVED: local, request and app. Replacements for these are:
* request, local.request: Tipfy.request, a class attribute in the WSGI app.
* app, local.app: Tipfy.app, a class attribute in the WSGI app.
* local: request.context and request.registry, dictionaries set for a
request.
- REMOVED: old aliases: WSGIApplication (Tipfy) and REQUIRED_CONFIG
(REQUIRED_VALUE)
Version 0.5.9 - July 1st, 2010
==============================
- Small improvement in get_config(): previously when you called
get_config without passing a key value, and the module was partially
configured by the user, it would return only the partial configuration.
Now if the module defaults weren't previously loaded, it will always be
loaded and set as default in config. This way, get_config('module') will
return the full dictionary of defaults for 'module', plus user configured
values.
- Added argument 'loaded' to Config constructor, to set the initially loaded
modules.
- Updated SDK URL to 1.3.5 in buildout.cfg.
Version 0.5.8 - June 30, 2010
=============================
- Added request.registry, as we slowly move away from thread-local variables.
Version 0.5.7 - June 27, 2010
=============================
- REMOVED: normalize_callable(). Unused.
- Renamed Tipfy.context to Tipfy.registry, as the purpose is to serve as a
registry for instances reused by the app, like Jinja2 or Genshi environments.
Version 0.5.6 - June 22, 2010
=============================
- REMOVED: RegexConverter. Unused and undocumented.
- REMOVED: wsgi_app_id config key. Unused.
- Middleware lists can now also have middleware instances. This allows
different instances of same middleware classes to be used with different
configuration:
my_middleware = MyMiddleware(foo='bar')
class MyRequestHandler(RequestHandler):
middleware = [my_middleware]
# ...
my_middleware2 = MyMiddleware(foo='zing')
class MyRequestHandler2(RequestHandler):
middleware = [my_middleware2]
# ...
- Fixed using tipfy with zipimport. For whatever reason py_zipimport fails to
load werkzeug modules if werkzeug package is not imported first. This is
probably related to how werkzeug lazy-loads modules -- an edge case not
covered by py_zimpimport.
Version 0.5.5 - June 2nd, 2010
==============================
- All .ext packages were moved to separate releases. Tipfy is again a single
file with a single dependency (Werkzeug), as it was in the beginning.
Version 0.5.4 - May 27, 2010
============================
Bug fix release following 0.5.3.
- REMOVED 'pre_run_app' hook. Use post_make_app instead:
def post_make_app(self, app):
# Wrap the callable, so we keep a reference to the app...
app.wsgi_app = my_middleware(app.wsgi_app)
# ...and return the original app.
return app
- IMPROVED tipfy.ext.appstatts and tipfy.ext.debugger: middleware is set on
'post_make_app'.
Version 0.5.3 - May 27, 2010
============================
Backwards compatibility warnings
--------------------------------
- ADDED: RequestHandler.__init__(app, request), setting references to current
WSGIApplication and Request in the handler. If you implemented __init__() on
RequestHandler, please update it to accept these arguments:
class MyRequestHandler(RequestHandler):
def __init__(self, app, request):
super(MyRequestHandler, self).__init__(app, request)
...
We now have access to the URL rule and rule arguments that matched on
__init__(), and can read app configuration without relying on local.
- CHANGED: the signature of RequestHandler.dispatch(), as a consequence of
adding __init__() to the handler class. Request method and rule arguments
are taken from the request set on __init__().
- REMOVED: tipfy.ext.session.MessagesMixin.set_form_error(). It required
i18n, which requires Babel. Sessions should not depend on i18n. Now they
don't. Please implement it on a separate mixin or base handler if you used
it.
- We're now slowly getting rid of globals and local is the first target, as it
doesn't make sense on App Engine.
While local.request and local.app still works, you should start using
Tipfy.request and Tipfy.app if globals are required in helper functions (they
are now available in the handler, which should cover most use cases).
Tipfy.request and Tipfy.app are set and cleaned on each request. It is
fast and perfectly valid on App Engine, but unfortunately this is not a
good idea outside of App Engine where you need to take care of threading.
So an application using Tipfy outside of App Engine needs to setup a proxy on
these attributes pointing to a thread local. This monkeypatch covers it all:
from werkzeug import Local
local = Local()
def set_wsgi_app(self):
local.app = self
def set_request(self, request):
local.request = request
def cleanup(self):
local.__release_local__()
Tipfy.set_wsgi_app = set_wsgi_app
Tipfy.set_request = set_request
Tipfy.cleanup = cleanup
Tipfy.app = local('app')
Tipfy.request = local('request')
This makes Tipfy.app and Tipfy.request thread-safe outside of App Engine.
tipfy.routing
-------------
- CHANGED: Added _anchor keyword argument to url_for() and redirect_to(), to
append an anchor to the generated URL. Also keyword arguments in these two
functions are now prefixed with a '_':
url_for(endpoint, _full=False, _method=None, _anchor=None, **kwargs)
redirect_to(endpoint, _method=None, _anchor=None, _code=302, **kwargs)
This is just a sanity measure to avoid collisions with variables set in
rules. The old, non-prefixed keywords are still accepted, but they should
be removed on 1.0.
- ADDED: request.url_for(). tipfy.url_for() just calls request.url_for().
tipfy.ext.i18n
--------------
- ADDED: functions to ext.i18n: get_timezone_name(), parse_date(),
parse_datetime() and parse_time().
- IMPROVED: All datetime and number format functions in ext.i18n now accept a
locale argument. If not set, uses the currently loaded locale (as before).
- ADDED: babel.cfg to the project directory, with configuration to extract
translation messages using pybabel. Also added locale directory to the app
dir.
tipfy.application
-----------------
- ADDED: a Request object that extends werkzeug's Request. This is backwards
compatible and stores url_adapter, matched rule and rule arguments.
app.url_adapter, app.rule and app.rule_args are still set, but they will be
removed on 1.0.
- ADDED: app.dev attribute, as a shortcut to the development flag set in
config.
- ADDED: app.get_config(). tipfy.get_config() just calls app.get_config().
- FIXED: logging debug level is set correctly now when in development.
- ADDED some ideas from Flask:
- Local variables are not cleaned when in development and an exception is
raised. This allows the debugger to still access request and other
variables from local in the interactive shell.
- Added a wsgi_app() function to WSGIApplication, wrapping __call__().
- Added a make_response() method to WSGIApplication, so that handlers
can return not only a Response object.
- Refactoring: split pre_dispatch/dispatch/post_dispatch into separate
functions. Makes it easier to override these methods in a middleware.
- Added function get_test_client() to return a werkzeug.Client for the wsgi
app.
- Added function ext.jinja2.get_template_attribute().
- ADDED: a Response object that extends werkzeug's Response, with default
mimetype set to 'text/html'.
- REMOVED:
- tipfy.response and 'extensions' configuration key. They were deprecated
since 0.5 and not useful at all since then.
- tipfy.local_manager. No longer needed since latest Werkzeug.
Miscelaneous
------------
- FIXED: XMPP handlers. Now fully tested.
- IMPROVED: render_json_response() now accepts all arguments and keyword
arguments accepted by simplejson.dumps().
- ADDED: tipfy.ext.mail, a simple RequestHandler for inbound mail.
Version 0.5.2 - May 06, 2010
============================
- Added a buildout setup to manage external dependencies. It is now
the preferred method for setting and updating tipfy and app libraries.
A full build will still be provided, though.
- Experimental support for loading all libraries using zipimport. The buildout
setup is capable of generating the zip and it is included in sys.path by
default. (issue #12)
- Tipfy can now be installed using easy_install.
- Fixed bug in ext.taskqueue.Mapper that would prevent changes from being
written to the datastore. (Kaelten)
- Fixed debugger interactive console which was not working since Werkzeug 0.6.
(issue #11)
- Fixed ext.blobstore, broken since SDK 1.3.3 which made some previously
public blobstore functions protected.
- REMOVED: tipfy.application.PatchedCGIHandler. The CGIHandler bug was fixed in
the 1.3.2 SDK.
Version 0.5.1 - April 18, 2010
==============================
- Upgraded Werkzeug to 0.6.1.
- Upgraded Jinja2 to 2.4.
- Fixed bug in ext.auth.is_current_user_admin(). Thanks, danil.
- Added get_locale() to tipfy.ext.i18n. Internally it now uses get_locale()
instead of local.locale directly, so that locales are autoloaded when not set.
Version 0.5 - Codename Spiff - April 10, 2010
=============================================
- Minor bugs fixed in the released candidate, some more docs added, and we are
good to go.
Version 0.5rc - April 03, 2010
==============================
- This is a major release with several backwards compatibility breaks. API
and architecture consistency was one of the major goals -- better to break
things sooner than later.
- Added a middleware system for handlers: handlers can now hook pre, post and
handle exception routines in the handler class itself. Very useful to make
base handlers with similar requirements and characteristics, without adding
overhead to non-related, simpler handlers. A few initial middleware classes
were added:
- AppstatsMiddleware
- AuthMiddleware
- DebuggerMiddleware
- I18nMiddleware
- SessionMiddleware
This deprecates several functionalities performed by app hooks before.
While hooks are still useful to wrap and extend WSGIApplication, middleware
applied directly to handlers are more appropriate in several use cases.
Thanks to Thomas Johansson (prencher) for the invaluable feedback on this.
- The previous 'extensions' system for the WSGI app now uses the same middleware
system used by the handlers. You can register middleware for the WSGI app and
these classes can also act as handler middleware.
- Added tipfy.ext.appstats, a middleware to use the appstats profiling tool.
- Added tipfy.ext.blobstore, with handler mixin classes to handle blobstore
upload and serving.
- Added tipfy.ext.xmpp, with base handlers for XMPP bots.
- Added several other mixin classes. Each of them add a couple of attributes
or methods to a request handler. The full list of mixins:
- AclMixin
- BlobstoreDownloadMixin
- BlobstoreUploadMixin
- Jinja2Mixin
- MakoMixin
- MessagesMixin
- SessionMixin
- Added some new db.Model properties to tipfy.ext.db:
- JsonProperty
- TimezoneProperty (thanks to Thomas Johansson for this one)
- Added post_make_app application hook.
- tipfy.ext.session was rewritten from scratch. It now works as a provider of
sessions and related stuff, such as signed flash messages and secure cookies.
- tipfy.ext.messages was removed and the existing functionality (flash messages
and messages container) was merged into tipfy.ext.session.
- tipfy.ext.user was renamed to tipfy.ext.auth.
- tipfy.ext.i18n doesn't require initialization anymore; it is initialized when
first used. Locale for the current request can be automatically loaded using
several configurable methods (taking arguments from GET, POST, cookies or
URL parameters).
- Added number formatting functions to tipfy.ext.i18n: format_number,
format_decimal, format_currency, format_percent, format_scientific,
parse_number, parse_decimal.
- URL rules are no longer stored in memcache. This can be done in urls.py if
one wants it. Tipfy core won't make *any* API calls anymore.
- Added a directory for examples in Tipfy's repository, compiling all examples
from tutorials and some new ones.
- Several improvements everywhere, and a lot more documentation and unit test
coverage.