Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use pathlib.Path for template paths #244

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading