Core Functionality

Core functionality for the fh-posts package.

Post class


source

Post

 Post (path:pathlib.Path, metadata:fastcore.basics.AttrDict, slug:str)

Represents a blog post with its metadata and content. This class provides methods to render the post content with optional code execution and formatting options.

Type Details
path Path The path to the post
metadata AttrDict The metadata for the post
slug str The slug for the post

source

Post.render

 Post.render (open_links_new_window:bool=False, live_label:bool=True)

Render the post content with code execution as specified by tags.

Type Default Details
open_links_new_window bool False Whether to open links in a new window
live_label bool True Whether to show the live label
Returns NotStr

Front Matter

Front matter is the metadata that is stored in the file before the content. In a notebook, it is the YAML frontmatter that is stored in the first cell as a raw cell. In a markdown file, it is the YAML frontmatter that is stored in the file before the content.

The extract_frontmatter function is used to extract the frontmatter from a file.

The extract_notebook_frontmatter function is used to extract the frontmatter from a notebook.

Sample front matter:

---
title: WorldTest
summary: A test of a .md file
date: February 25, 2025
tags:
  - python
  - fasthtml
  - monsterui
---

source

extract_frontmatter

 extract_frontmatter (file_path:pathlib.Path)

Extract YAML frontmatter from a Markdown file.

Type Details
file_path Path The path to the file to extract the frontmatter from
Returns AttrDict
md_path = Path('posts/md_test.md')
md_metadata = extract_frontmatter(md_path)
md_metadata
{ 'date': 'February 25, 2025',
  'summary': 'A test of a .md file',
  'tags': ['python', 'fasthtml', 'monsterui'],
  'title': 'MD Test'}

Because extract_frontmatter returns an AttrDict, you can access the metadata using keys or attributes.

test_eq(md_metadata['date'], 'February 25, 2025')
test_eq(md_metadata.date, 'February 25, 2025')
assert isinstance(md_metadata.tags, list)

source

extract_notebook_frontmatter

 extract_notebook_frontmatter (file_path:pathlib.Path)

Extract YAML frontmatter from a Jupyter Notebook file.

Type Details
file_path Path The path to the notebook to extract the frontmatter from
Returns AttrDict
nb_path = Path('posts/nb_test.ipynb')
nb_metadata = extract_notebook_frontmatter(nb_path)
nb_metadata
{ 'date': 'February 24, 2025',
  'summary': 'A test of an .ipynb file',
  'tags': ['python', 'fasthtml', 'monsterui'],
  'title': 'NB Test'}
test_eq(nb_metadata['title'], 'NB Test')
test_eq(nb_metadata.summary, 'A test of an .ipynb file')

Once we have the metadata, we can create a Post object and test that we can access the metadata using keys or attributes.

md_post = Post(md_path, md_metadata, 'world')
nb_post = Post(nb_path, nb_metadata, 'hello')
test_eq(md_post['date'], 'February 25, 2025')
test_eq(nb_post.date, 'February 24, 2025')
assert isinstance(md_post.tags, list)

source

get_post_date

 get_post_date (post, date_format='%B %d, %Y')

Extract date from post for sorting.

Type Default Details
post The post to get the date from
date_format str %B %d, %Y The format string for the date i.e. “January 01, 2025”
Returns datetime
test_eq(get_post_date(md_post), datetime.strptime('February 25, 2025', "%B %d, %Y"))
test_eq(get_post_date(nb_post), datetime.strptime('February 24, 2025', "%B %d, %Y"))

source

load_posts

 load_posts (path:str|pathlib.Path, date_format:str='%B %d, %Y')

Load all posts from the specified directory. Extracts frontmatter from markdown files and notebooks with extract_frontmatter and extract_notebook_frontmatter respectively. Specify optional date format string for get_post_date to sort posts by date.

Type Default Details
path str | pathlib.Path The path to the directory containing the posts
date_format str %B %d, %Y The format string for the date i.e. “January 01, 2025”
Returns List

Posts are loaded and sorted by date in reverse order so newest post come first.

posts = load_posts('posts')
posts
[Post(slug='md_test', title='MD Test', path='posts/md_test.md'),
 Post(slug='nb_test', title='NB Test', path='posts/nb_test.ipynb')]
print([post.date for post in posts])
['February 25, 2025', 'February 24, 2025']
test_eq(posts[0].date, 'February 25, 2025')

Helper Functions


source

parse_tag

 parse_tag (tag_str:str)

Parse a tag string into a dict of tag properties e.g., ‘python:run:hide-in’.

tags = 'python:run:hide'
processed_tags = parse_tag(tags)
processed_tags
{'run': True, 'hide_in': True, 'hide_out': True, 'hide_call': False}

parse_tag parses the tag that is used to control the execution of the code in the notebook and markdown files. The tag is a string that contains the tag name and optional properties separated by colons. In markdown files the tag follows the triple backticks that start the code block and in notebooks the tag is the first line of the code block and is prefixed with #|. The properties are:

run: Whether to run the code

hide_in: Whether to hide the input code

hide_out: Whether to hide the output

hide_call: Whether to hide the final call line

The tag is used in the markdown and notebook files to control the execution of the code.


source

execute_code

 execute_code (code:str, namespace:Optional[Dict]=None)

Execute Python code and return the execution result.

Type Default Details
code str The code to execute
namespace Optional None Optional namespace to use for execution
Returns Dict Returns a dict with keys: output (captured stdout), error (captured stderr), result (last expression result), namespace (updated namespace)
code_samp = """
def greeting(name):
    print(f"Debug: Function called with name: {name}")
    return f"Hello, {name}!"

greeting("Alice")"""
test_eq(execute_code(code_samp)['result'], "Hello, Alice!")
assert execute_code(code_samp)['output'].startswith("Debug:")

The output is captured from the stdout and stderr streams and would be what is printed to the console. The result is the value of the last expression in the code. Note that in a notebook environment the output can be captured twice but this doesn’t happen at run time.


source

process_code_block

 process_code_block (tag_props:Dict[str,bool], code:str,
                     namespace:Optional[Dict]=None)

Process a code block based on its tag properties.

Type Default Details
tag_props Dict Dict of tag properties
code str Python code to execute
namespace Optional None Optional namespace to use for execution
Returns Dict Returns a dict with keys: show_code, show_output, code_html, output_html, namespace
code_block_dict =  process_code_block(parse_tag('python:run:hide'), code_samp)
test_eq(code_block_dict['show_code'], False)
test_eq(code_block_dict['show_output'], False)
test_eq(code_block_dict['code_html'], '')

source

render_markdown_post

 render_markdown_post (post:__main__.Post,
                       open_links_new_window:bool=False,
                       live_label:bool=True)

Render a Markdown post with code execution.

Type Default Details
post Post The post to render
open_links_new_window bool False
live_label bool True
Returns NotStr The rendered HTML in a NotStr object (FastHTML object)

source

render_notebook_post

 render_notebook_post (post:__main__.Post,
                       open_links_new_window:bool=False,
                       live_label:bool=True)

Render a Jupyter Notebook post with code execution.

Type Default Details
post Post The post to render
open_links_new_window bool False
live_label bool True
Returns NotStr