Permalink
Browse files

Added ReadersCorner, and improved caching.

  • Loading branch information...
mhlakhani committed Feb 7, 2014
1 parent c0e2dfe commit 8d067f42eba9eed7e7ea29132089de35251383a3
Showing with 145 additions and 5 deletions.
  1. +14 −0 README.md
  2. +130 −4 halwa.py
  3. +1 −1 setup.py
@@ -83,6 +83,11 @@ It will simply render the given template. It is intended for simple pages (such
This will take each *tag* in the *tags* dictionary that has been passed in, and render the template page
with that *tag*.

### ReadersCornerPage

This will take each *year* in the *readerscorner* dictionary that has been passed in, and render a copy of template page
for each *month* in that *year*.

### BlogPost

This will automatically generate a *slug* for the content, based on the date in the metadata and the filename.
@@ -116,6 +121,15 @@ This processor generates post archives, saving them in the *key* attribute of th
is a dictionary (of years), where each year is a dictionary (of months); and each month is a dictionary of posts
in that month, sorted by day (in reverse order if *reverse* is true).

### ReadersCorner

This processor generates the readers corner feed, saving it in the *key* attribute of the *data* dictionary. It
will also generate a sidebar with links (using the provided *route*) for each year and month,
saving it in the *sidebarkey* attribute of the *data* dictionary.

The archive is a dictionary (of years), where each year is a dictionary (of months); and each month is a dictionary (of days);
each day is a dictionary of links, sorted by time (in reverse order if *reverse* is true).

### RSSFeed

This processor generates an RSSFeed, putting it in the *key* attribute of the *data* dictionary. It will put
134 halwa.py
@@ -99,6 +99,7 @@ def update(self, data):
self.data[key] = v

self.data['url_for'] = self.app.url_for
self.data['len'] = len
self.data.update(self.metadata)

def render(self):
@@ -108,7 +109,7 @@ def render(self):
if self.dependencies is not None:
deps.extend(self.dependencies)
status = self.app.cache.need_update(path, deps)

if status != 'Ignore':
if self.content is None:
self.load_content()
@@ -145,6 +146,15 @@ def _render(self):
return self.template

def render(self):

# Special case cause this is expensive
updated = False
for dep in (self.dependencies + [self.path]):
if dep in self.app.cache.updated_content:
updated = True

if not updated:
return []

rets = []
for tag in self.data['tags']:
@@ -155,6 +165,44 @@ def render(self):

return rets

class ReadersCornerPage(DynamicContent):

def __init__(self, app, path, mappings=None, dependencies=None):
super(ReadersCornerPage, self).__init__(app, path, mappings, dependencies)
self.template = None

def load(self):
return super(ReadersCornerPage,self).load()

def _render(self):
if self.template is None:
self.template = self.app.jinja_env.hamlish_from_string(self.content)

return self.template

def render(self):

# Special case cause this is expensive
updated = False
for dep in (self.dependencies + [self.path]):
if dep in self.app.cache.updated_content:
updated = True

if not updated:
return []

rets = []
archives = self.data['readerscorner']
for (year, yeararchive) in archives.items():
for (month, montharchive) in yeararchive.items():
self.data['year'] = year
self.data['month'] = month
self.data['montharchive'] = montharchive
self.data['monthname'] = calendar.month_name[int(month)]
rets.extend(super(ReadersCornerPage, self).render())

return rets

class BlogPost(DynamicContent):

def __init__(self, app, path, mappings=None, dependencies=None):
@@ -214,10 +262,10 @@ def process(self, content, data):
lis.extend(post.metadata.get(self.key, []))

tags = []
for (tag, count) in sorted(Counter(lis).items(), reverse=self.reverse, key=lambda k_v: k_v[1]):
for (tag, count) in sorted(Counter(lis).items(), reverse=self.reverse, key=lambda k_v: (k_v[1], k_v[0])):
tagged = [p.metadata for p in posts if tag in p.metadata[self.datakey]]
tagged = sorted(tagged, reverse=self.reverse, key=lambda p: p[self.sortkey])
tags.append(OrderedDict(tag=tag, count=count, posts=tagged, url=self.app.url_for(self.route, tag=tag)))
tags.append(OrderedDict([('tag',tag), ('count',count), ('posts', tagged), ('url', self.app.url_for(self.route, tag=tag))]))

data[self.key] = tags
return data
@@ -299,6 +347,74 @@ def process(self, content, data):
data[self.key] = archives
return data

class ReadersCorner(Processor):

def __init__(self, app, filename, filter=None, key='readerscorner', sidebarkey='readerscornersidebar', route='readerscorner', reverse=True):
super(ReadersCorner, self).__init__(app)
self.filename = filename
self.filter = filter
self.key = key
self.sidebarkey = sidebarkey
self.route = route
self.reverse = True

def process(self, content, data):

status, val = self.app.cache.get_file(self.filename)
if status == 'Cached':
data[self.key] = val[self.key]
data[self.sidebarkey] = val[self.sidebarkey]
return data

source = []
with open(self.filename) as input:
source = json.load(input)

entries = []
for entry in source:
if self.filter is not None:
entry = self.filter(entry)
if entry is None:
continue
tm = time.strptime(entry['created_time'], '%Y-%m-%dT%H:%M:%S+0000')
entry['year'] = tm.tm_year
entry['month'] = tm.tm_mon
entry['day'] = tm.tm_mday
entry['timestamp'] = time.strftime('%H:%M:%S', tm)
if entry.get('description', '') == 'null':
entry['description'] = None
entries.append(entry)

years = sorted((k for k in set(e['year'] for e in entries)), reverse=self.reverse)

archives = OrderedDict()
sidebar = OrderedDict()

for year in years:
yeararchive = OrderedDict()
sidebar[year] = OrderedDict()
yearentries = [e for e in entries if e['year'] == year]

months = sorted((k for k in set(e['month'] for e in yearentries)), reverse=self.reverse)
for month in months:
montharchive = OrderedDict()
monthentries = [e for e in yearentries if e['month'] == month]
days = sorted((k for k in set(e['day'] for e in monthentries)), reverse=self.reverse)
for day in days:
dayentries = [e for e in monthentries if e['day'] == day]
montharchive[day] = sorted(dayentries, reverse=self.reverse, key=lambda e: e['timestamp'])
yeararchive[month] = montharchive
linkstring = '%s (%s)' % (calendar.month_name[int(month)], sum(len(v) for k,v in montharchive.items()))
sidebar[year][linkstring] = self.app.url_for(self.route, year=year, month=month)

archives[year] = yeararchive

data[self.key] = archives
data[self.sidebarkey] = sidebar
self.app.cache.put_file(self.filename, {self.key : archives, self.sidebarkey : sidebar})

return data

class RSSFeed(Processor):

def __init__(self, app, count=5, key='blogrss', title='title', link='link', description='description', sortkey='date', reverse=True):
@@ -335,7 +451,7 @@ def __init__(self, app, root='', key='sitemap'):
def process(self, content, data):

urls = []
for item in (c for c in content if (type(c) != TagPage) and (type(c) != StaticContent)):
for item in (c for c in content if (type(c) != TagPage) and (type(c) != StaticContent) and (type(c) != ReadersCornerPage)):
url = self.root + self.app.get_output_path(self.app.url_for(**item.metadata)).replace(self.app.directories['output'], '')
urls.append(url)

@@ -346,6 +462,7 @@ class Cache(object):

def __init__(self, path):
self.store = shelve.open(path)
self.updated_content = []

def get_file(self, path):
val = None
@@ -361,6 +478,9 @@ def get_file(self, path):
if mtime < val['mtime']:
status = 'Cached'
val = val['value']

if status == 'Read':
self.updated_content.append(path)

return (status, val)

@@ -377,6 +497,7 @@ def put_content(self, name, value):
v = self.store.get(key, {'value': None})
if v['value'] != value:
self.store[key] = val
self.updated_content.append(name)

def need_update(self, path, dependencies=None):
if not os.path.exists(path):
@@ -393,6 +514,11 @@ def need_update(self, path, dependencies=None):

if mtime < max(mtimes):
return 'Modified'

for dep in dependencies:
if dep in self.updated_content:
return 'Modified'

return 'Ignore'

def shutdown(self):
@@ -1,7 +1,7 @@
from setuptools import setup
setup(
name = "Halwa",
version = "0.1.4",
version = "0.1.5",
py_modules = ['halwa'],

install_requires = ['Hamlish-Jinja>=0.3.0','Jinja2>=2.6', 'Markdown>=2.2.1'],

0 comments on commit 8d067f4

Please sign in to comment.