Skip to content

Commit

Permalink
feat: use pathlib.Path for template paths
Browse files Browse the repository at this point in the history
This commit modifies the django-pattern-library to use pathlib.Path for template paths. This ensures that the paths are handled consistently across different operating systems, including Windows.
The following functions have been modified to use pathlib.Path:
path_to_section()
section_for()
get_template_dirs()
get_pattern_config_str()
get_pattern_markdown()
Additionally, the TemplateRenderer.get_pattern_templates() method has been updated to use pathlib.Path for template paths.
possibly related issue: torchbox#116
  • Loading branch information
reedjones committed Mar 7, 2024
1 parent dfc31df commit a40f0c3
Showing 1 changed file with 157 additions and 93 deletions.
250 changes: 157 additions & 93 deletions pattern_library/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

import markdown
import yaml
import pathlib
from pathlib import Path

from pattern_library import (
get_pattern_context_var_name,
Expand All @@ -22,17 +24,20 @@
from pattern_library.exceptions import TemplateIsNotPattern



from django.utils.html import escape

def path_to_section():
section_config = get_sections()
sections = {}
for section, paths in section_config:
for path in paths:
sections[path] = section
sections[Path(path)] = section
return sections


def is_pattern(template_name):
if not template_name.endswith(get_pattern_template_suffix()):
if not str(template_name).endswith(get_pattern_template_suffix()):
return False

section, path = section_for(os.path.dirname(template_name))
Expand All @@ -51,7 +56,7 @@ def is_pattern_library_context(context):
def section_for(template_folder):
paths = path_to_section()
for path in paths:
if template_folder.startswith(path):
if str(template_folder).startswith(str(path)):
return paths[path], path
return None, None

Expand Down Expand Up @@ -79,77 +84,6 @@ def get_template_dirs():
return template_dirs


def get_pattern_templates():
templates = base_dict()
template_dirs = get_template_dirs()

for lookup_dir in template_dirs:
for root, dirs, files in os.walk(lookup_dir, topdown=True):
# Ignore folders without files
if not files:
continue

base_path = os.path.relpath(root, lookup_dir)
section, path = section_for(base_path)

# It has no section, ignore it
if not section:
continue

found_templates = []
for current_file in files:
pattern_path = os.path.join(root, current_file)
pattern_path = os.path.relpath(pattern_path, lookup_dir)

if is_pattern(pattern_path):
template = get_template(pattern_path)
pattern_config = get_pattern_config(pattern_path)
pattern_name = pattern_config.get("name")
pattern_filename = os.path.relpath(
template.origin.template_name,
base_path,
)
if pattern_name:
template.pattern_name = pattern_name
else:
template.pattern_name = pattern_filename

template.pattern_filename = pattern_filename

found_templates.append(template)

if found_templates:
lookup_dir_relpath = os.path.relpath(root, lookup_dir)
sub_folders = os.path.relpath(lookup_dir_relpath, path)
templates_to_store = templates
for folder in [section, *sub_folders.split(os.sep)]:
try:
templates_to_store = templates_to_store["template_groups"][
folder
]
except KeyError:
templates_to_store["template_groups"][folder] = base_dict()
templates_to_store = templates_to_store["template_groups"][
folder
]

templates_to_store["templates_stored"].extend(found_templates)

# Order the templates alphabetically
for templates_objs in templates["template_groups"].values():
templates_objs["template_groups"] = order_dict(
templates_objs["template_groups"]
)

# Order the top level by the sections
section_order = [section for section, _ in get_sections()]
templates["template_groups"] = order_dict(
templates["template_groups"], key_sort=lambda key: section_order.index(key)
)

return templates


def get_pattern_config_str(template_name):
replace_pattern = "{}$".format(get_pattern_template_suffix())
context_path = re.sub(replace_pattern, "", template_name)
Expand Down Expand Up @@ -227,27 +161,157 @@ def render_pattern(request, template_name, allow_non_patterns=False, config=None
return render_to_string(template_name, request=request, context=context)


def get_template_ancestors(template_name, context=None, ancestors=None):
"""
Returns a list of template names, starting with provided name
and followed by the names of any templates that extends until
the most extended template is reached.
"""
if ancestors is None:
ancestors = [template_name]
def get_renderer():
return TemplateRenderer

if context is None:
context = Context()

pattern_template = get_template(template_name)
class TemplateRenderer:
@classmethod
def get_pattern_templates(cls):
templates = base_dict()
template_dirs = get_template_dirs()

for node in pattern_template.template.nodelist:
if isinstance(node, ExtendsNode):
parent_template_name = node.parent_name.resolve(context)
ancestors.append(parent_template_name)
get_template_ancestors(
parent_template_name, context=context, ancestors=ancestors
for lookup_dir in template_dirs:
for root, dirs, files in os.walk(lookup_dir, topdown=True):
# Ignore folders without files
if not files:
continue

base_path = os.path.relpath(root, lookup_dir)
section, path = section_for(Path(base_path))

# It has no section, ignore it
if not section:
continue

found_templates = []
for current_file in files:
pattern_path = Path(root) / Path(current_file)
pattern_path = Path(pattern_path.relative_to(lookup_dir))

if is_pattern(pattern_path):
template = get_template(pattern_path)
pattern_config = get_pattern_config(pattern_path)
pattern_name = pattern_config.get("name")
pattern_filename = Path(template.origin.template_name).relative_to(base_path)

if pattern_name:
template.pattern_name = pattern_name
else:
template.pattern_name = pattern_filename

template.pattern_filename = pattern_filename

found_templates.append(template)

if found_templates:
lookup_dir_relpath = Path(root).relative_to(lookup_dir)
sub_folders = Path(lookup_dir_relpath).relative_to(path)
templates_to_store = templates
for folder in [section, *str(sub_folders).split(os.sep)]:
try:
templates_to_store = templates_to_store["template_groups"][
folder
]
except KeyError:
templates_to_store["template_groups"][folder] = base_dict()

templates_to_store = templates_to_store["template_groups"][
folder
]

templates_to_store["templates_stored"].extend(found_templates)

# Order the templates alphabetically
for templates_objs in templates["template_groups"].values():
templates_objs["template_groups"] = order_dict(
templates_objs["template_groups"]
)
break

return ancestors
# Order the top level by the sections
section_order = [section for section, _ in get_sections()]
templates["template_groups"] = order_dict(
templates["template_groups"], key_sort=lambda key: section_order.index(key)
)

return templates

@classmethod
def get_pattern_source(cls, template):
return cls._get_engine(template).get_pattern_source(template)

@classmethod
def get_template_ancestors(cls, template_name, context=None):
template = get_template(template_name)
return cls._get_engine(template).get_template_ancestors(template_name, context=context)

@classmethod
def _get_engine(cls, template):
if "jinja" in str(type(template)).lower():
return JinjaTemplateRenderer
return DTLTemplateRenderer

class DTLTemplateRenderer:
@staticmethod
def get_pattern_source(template):
return escape(template.template.source)

@classmethod
def get_template_ancestors(cls, template_name, context=None, ancestors=None):
"""
Returns a list of template names, starting with provided name
and followed by the names of any templates that extends until
the most extended template is reached.
"""
if ancestors is None:
ancestors = [template_name]

if context is None:
context = Context()

pattern_template = get_template(template_name)

for node in pattern_template.template.nodelist:
if isinstance(node, ExtendsNode):
parent_template_name = node.parent_name.resolve(context)
ancestors.append(parent_template_name)
cls.get_template_ancestors(
parent_template_name, context=context, ancestors=ancestors
)
break

return ancestors


class JinjaTemplateRenderer:
@staticmethod
def get_pattern_source(template):
with open(template.template.filename) as f:
source = escape(f.read())
return source

@classmethod
def get_template_ancestors(cls, template_name, context=None, ancestors=None):
"""
Returns a list of template names, starting with provided name
and followed by the names of any templates that extends until
the most extended template is reached.
"""
from jinja2.nodes import Extends

if ancestors is None:
ancestors = [template_name]

if context is None:
context = Context()

pattern_template = get_template(template_name)
#todo - make sure envrionment has context passed in
environment = pattern_template.template.environment
nodelist = environment.parse(pattern_template.name)
parent_template_name = nodelist.find(Extends)
if parent_template_name:
ancestors.append(parent_template_name)
cls.get_template_ancestors(parent_template_name, context=context, ancestors=ancestors)

return ancestors

0 comments on commit a40f0c3

Please sign in to comment.