Skip to content
This repository has been archived by the owner on Apr 18, 2020. It is now read-only.

Commit

Permalink
Refactored frontmatter deserializer as a class
Browse files Browse the repository at this point in the history
  • Loading branch information
palewire committed Jul 5, 2017
1 parent ca628f3 commit adeff8d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 77 deletions.
3 changes: 2 additions & 1 deletion bigbuild/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ def refresh_from_db(self):
"""
Reads in the frontmatter from metadata.yaml and syncs it with the object.
"""
yaml_obj = BigBuildFrontmatterDeserializer(self.slug, self.__class__.__name__)
deserializer = BigBuildFrontmatterDeserializer(self.slug, self.__class__.__name__)
yaml_obj = deserializer.deserialize()
for field in yaml_obj._meta.fields:
setattr(self, field.name, getattr(yaml_obj, field.name))
self.data_objects = yaml_obj.data_objects or {}
Expand Down
4 changes: 2 additions & 2 deletions bigbuild/models/pagelists.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ def get_page(slug, pagetype):
return None

# Create a Page object from the directory slug
return BigBuildFrontmatterDeserializer(slug, pagetype)
deserializer = BigBuildFrontmatterDeserializer(slug, pagetype)
return deserializer.deserialize()

def get_dynamic_pages(self):
"""
Returns a list of Page objects ready to be built
in this environment.
"""
logger.debug("Retrieving dynamic page list")
page_list = []
for d in os.listdir(self.dynamic_directory):
page = self.get_page(d, 'Page')
Expand Down
158 changes: 84 additions & 74 deletions bigbuild/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def get_dump_object(self, obj):
def end_serialization(self):
# Dump each object into the stream as as frontmatter
content = [frontmatter.dumps(o) for o in self.objects]
# Write out as text to the stream in a safe string format
[self.stream.write(six.text_type(chunk)) for chunk in content]

def get_metadata(self, obj):
Expand Down Expand Up @@ -112,82 +113,91 @@ def is_metadata_valid(self, metadata):
return False


def BigBuildFrontmatterDeserializer(slug, model_name='Page'):
class BigBuildFrontmatterDeserializer(object):
"""
Given the page to a YAML deserialize it from Jekyll's frontmatter format.
"""
model = apps.get_app_config('bigbuild').get_model(model_name)
obj = model.create(slug=slug, skip_create_directory=True)
try:
stream = open(obj.frontmatter_path, 'r')
post = frontmatter.load(stream)

# Set the basic frontmatter metadata
obj.headline = post.metadata['headline']
obj.byline = post.metadata['byline']
obj.description = post.metadata['description']
obj.image_url = post.metadata['image_url']
obj.pub_date = post.metadata['pub_date']
obj.published = post.metadata['published']
obj.show_in_feeds = post.metadata['show_in_feeds']

# Attach any extra stuff
try:
obj.extra = post.metadata['extra']
except KeyError:
obj.extra = {}

def __init__(self, slug, model_name='Page'):
logger.debug("Retrieving {} as {} object".format(
slug,
model_name
))
self.slug = slug
self.model_name = model_name
self.model = apps.get_app_config('bigbuild').get_model(model_name)

def deserialize(self):
obj = self.model.create(slug=self.slug, skip_create_directory=True)
try:
obj.data = post.metadata['data']
except KeyError:
obj.data = {}

# Pull in the content as is
obj.content = post.content

# Render it out as flat HTML
obj.content = obj.rendered_content

# Make sure the page has recommended metadata
# ... if it's ready to publish
if obj.pub_status in ['live', 'pending']:
if not obj.has_recommended_metadata():
logger.warn(MissingRecommendedMetadataWarning(obj))

# Extra stuff if this is a live Page model
if model_name == 'Page':
# Loop through any data files
for key, path in post.metadata.get('data', {}).items():

# Generate the path if it's stored in the default `data` directory
data_dir = os.path.join(obj.page_directory_path, 'data')
p = os.path.join(data_dir, path)
# If it doesn't exist, see if it's in another folder
if not os.path.exists(p):
p = os.path.join(obj.page_directory_path, path)
# If it's not there either, throw an error
stream = open(obj.frontmatter_path, 'r')
post = frontmatter.load(stream)

# Set the basic frontmatter metadata
obj.headline = post.metadata['headline']
obj.byline = post.metadata['byline']
obj.description = post.metadata['description']
obj.image_url = post.metadata['image_url']
obj.pub_date = post.metadata['pub_date']
obj.published = post.metadata['published']
obj.show_in_feeds = post.metadata['show_in_feeds']

# Attach any extra stuff
try:
obj.extra = post.metadata['extra']
except KeyError:
obj.extra = {}

try:
obj.data = post.metadata['data']
except KeyError:
obj.data = {}

# Pull in the content as is
obj.content = post.content

# Render it out as flat HTML
obj.content = obj.rendered_content

# Make sure the page has recommended metadata
# ... if it's ready to publish
if obj.pub_status in ['live', 'pending']:
if not obj.has_recommended_metadata():
logger.warn(MissingRecommendedMetadataWarning(obj))

# Extra stuff if this is a live Page model
if self.model_name == 'Page':
# Loop through any data files
for key, path in post.metadata.get('data', {}).items():

# Generate the path if it's stored in the default `data` directory
data_dir = os.path.join(obj.page_directory_path, 'data')
p = os.path.join(data_dir, path)
# If it doesn't exist, see if it's in another folder
if not os.path.exists(p):
logging.debug("Data file could not be found at %s" % p)

# Open the file
with codecs.open(p, 'r') as f:
# If it's a CSV file open it that way...
if p.endswith(".csv"):
obj.data_objects[key] = list(csv.DictReader(f))
# If it's a JSON file open it this way ...
elif p.endswith(".json"):
obj.data_objects[key] = json.load(f)
# If it's a YAML file open it t'other way ...
elif (p.endswith(".yml") or p.endswith(".yaml")):
obj.data_objects[key] = yaml.load(f)
elif p.endswith(".aml"):
obj.data_objects[key] = archieml.load(f)
# If it's none of those throw an error.
else:
logging.debug("Data file at %s not recognizable type" % path)

# Pass it out
return obj
except Exception as e:
# Map to deserializer error
six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
p = os.path.join(obj.page_directory_path, path)
# If it's not there either, throw an error
if not os.path.exists(p):
logging.debug("Data file could not be found at %s" % p)

# Open the file
with codecs.open(p, 'r') as f:
# If it's a CSV file open it that way...
if p.endswith(".csv"):
obj.data_objects[key] = list(csv.DictReader(f))
# If it's a JSON file open it this way ...
elif p.endswith(".json"):
obj.data_objects[key] = json.load(f)
# If it's a YAML file open it t'other way ...
elif (p.endswith(".yml") or p.endswith(".yaml")):
obj.data_objects[key] = yaml.load(f)
elif p.endswith(".aml"):
obj.data_objects[key] = archieml.load(f)
# If it's none of those throw an error.
else:
logging.debug("Data file at %s not recognizable type" % path)

# Pass it out
return obj
except Exception as e:
# Map to deserializer error
six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])

0 comments on commit adeff8d

Please sign in to comment.