Skip to content

Commit

Permalink
Refactor json custom decoder and encoder to class
Browse files Browse the repository at this point in the history
  • Loading branch information
devster31 committed Jul 18, 2016
1 parent 0067bf2 commit 5bde426
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 53 deletions.
10 changes: 6 additions & 4 deletions nofussbm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
# You should have received a copy of the GNU General Public License along with
# "No Fuss Bookmarks". If not, see <http://www.gnu.org/licenses/>.

from logging import StreamHandler, Formatter, getLogger, DEBUG
from logging import StreamHandler, Formatter, DEBUG
from os import environ

from flask import Flask, make_response, request, g, redirect, url_for, abort, render_template
from flask import Flask, make_response, request, redirect, url_for, abort, render_template
from flask.ext.pymongo import PyMongo

from pymongo.errors import OperationFailure
Expand All @@ -41,6 +41,9 @@ class Config( object ):
from .api import api
from .helpers import query_from_dict
from .tags import tags
from .json import NofussbmJSONEncoder, NofussbmJSONDecoder
app.json_encoder = NofussbmJSONEncoder
app.json_decoder = NofussbmJSONDecoder

# Register APIs blueprint and setup {before,teardown}_request

Expand All @@ -58,7 +61,7 @@ class Config( object ):

stderr_handler = StreamHandler()
stderr_handler.setLevel( DEBUG )
stderr_handler.setFormatter( Formatter( '%(asctime)s [%(process)s] [%(levelname)s] [Flask: %(name)s] %(message)s','%Y-%m-%d %H:%M:%S' ) )
stderr_handler.setFormatter( Formatter( '%(asctime)s [%(process)s] [%(levelname)s] [Flask: %(name)s] %(message)s', '%Y-%m-%d %H:%M:%S' ) )
app.logger.addHandler( stderr_handler )
app.logger.setLevel( DEBUG )

Expand Down Expand Up @@ -136,7 +139,6 @@ def list( ident ):
if list_appearance == 'html':
for bm in list_query( email, bookmarks_per_page ):
date = bm[ 'date-modified' ]
print bm
result.append( ( date.strftime( '%Y-%m-%d' ), bm[ 'url' ], bm[ 'title' ], bm[ 'tags' ], bm[ '_id' ] ) )
if content_only:
return render_template( 'list-content.html', bookmarks = result )
Expand Down
10 changes: 3 additions & 7 deletions nofussbm/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
# You should have received a copy of the GNU General Public License along with
# "No Fuss Bookmarks". If not, see <http://www.gnu.org/licenses/>.

import hmac
import re

from base64 import b64encode, b64decode
from datetime import datetime
from functools import wraps
from hashlib import sha1
import hmac
import re
from urlparse import parse_qs

from flask import Blueprint, make_response, request, g, json, abort
Expand All @@ -35,11 +36,6 @@
RANGE_RE = re.compile( r'bookmarks=(\d+)(-(\d+))?' )


# Hacks (somehow horrible) to personalize decoding in Flask request.json

from .helpers import setup_json
setup_json( json )

def myjsonify( data = None, code = 200, headers = None ):
data = [] if not data else data
response = make_response( json.dumps( data, indent = 4, sort_keys = True, ensure_ascii = False ) + '\n', code )
Expand Down
42 changes: 0 additions & 42 deletions nofussbm/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,13 @@
# You should have received a copy of the GNU General Public License along with
# "No Fuss Bookmarks". If not, see <http://www.gnu.org/licenses/>.

from datetime import datetime
from email.mime.text import MIMEText
from json import JSONEncoder, JSONDecoder
from smtplib import SMTP

from bson.objectid import ObjectId, InvalidId

from . import Config

DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f'

ALLOWED_KEYS = set(( 'title', 'url', 'id', 'tags', 'date-added', 'date-modified' ))

def to_id( id_as_str ):
res = None
Expand All @@ -48,43 +43,6 @@ def query_from_dict( email, dct ):
query[ 'title' ] = { '$regex': dct[ 'title' ], '$options': 'i' }
return query

def setup_json( json ):

def object_hook( dct ):
res = {}
for key, value in dct.items():
if key not in ALLOWED_KEYS: continue
if key == 'id': res[ 'id' ] = to_id( value )
elif key == 'tags': res[ 'tags' ] = map( lambda _: _.strip(), value.split( ',' ) )
elif key.startswith( 'date-' ):
try:
res[ key ] = datetime.strptime( value, DATETIME_FORMAT )
except:
pass
else:
res[ key ] = value
return res

class Encoder( JSONEncoder ):
def default(self, obj):
if isinstance( obj, datetime ):
return datetime.strftime( obj, DATETIME_FORMAT )
if isinstance( obj, ObjectId ):
return str( obj )
return JSONEncoder.default( self, obj )

prev_dumps = json.dumps
prev_loads = json.loads

def _dumps( *args, **kwargs ):
kwargs.update( { 'cls': Encoder } )
return prev_dumps( *args, **kwargs )
def _loads( *args, **kwargs ):
return prev_loads( *args, object_hook = object_hook, **kwargs )

json.dumps = _dumps
json.loads = _loads


# Utility functions

Expand Down
59 changes: 59 additions & 0 deletions nofussbm/json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2011, Massimo Santini <santini@dsi.unimi.it>
#
# This file is part of "No Fuss Bookmarks".
#
# "No Fuss Bookmarks" is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# "No Fuss Bookmarks" is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# "No Fuss Bookmarks". If not, see <http://www.gnu.org/licenses/>.

from flask.json import JSONEncoder, JSONDecoder
from datetime import datetime
from bson.objectid import ObjectId
from .helpers import to_id

DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S.%f'


class NofussbmJSONEncoder(JSONEncoder):

def default(self, obj):
if isinstance(obj, datetime):
return datetime.strftime(obj, DATETIME_FORMAT)
if isinstance(obj, ObjectId):
return str(obj)
return JSONEncoder.default(self, obj)


class NofussbmJSONDecoder(JSONDecoder):

def __init__(self, *args, **kwargs):
self.ALLOWED_KEYS = set(['title', 'url', 'id', 'tags', 'date-added', 'date-modified'])
self.orig_object_hook = kwargs.pop("object_hook", None)
super(NofussbmJSONDecoder, self).__init__(*args, object_hook=self.custom_object_hook, **kwargs)

def custom_object_hook(self, dct):
res = dict()
for key, value in dct.items():
if key not in self.ALLOWED_KEYS:
continue
if key == 'id':
res['id'] = to_id(value)
elif key == 'tags':
res['tags'] = [_.strip() for _ in value.split(',')]
elif key.startswith('date-'):
try:
res[key] = datetime.strptime(value, DATETIME_FORMAT)
except:
pass
else:
res[key] = value
return res

0 comments on commit 5bde426

Please sign in to comment.