tinyssg 1.1.0__py3-none-any.whl → 1.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tinyssg/__init__.py CHANGED
@@ -7,6 +7,7 @@ import re
7
7
  import shutil
8
8
  import subprocess
9
9
  import sys
10
+ import textwrap
10
11
  import time
11
12
  import webbrowser
12
13
  from http.server import HTTPServer, SimpleHTTPRequestHandler
@@ -40,6 +41,12 @@ class TinySSGPage:
40
41
  """
41
42
  raise TinySSGException(f"The Page class corresponding to {self.__class__.__name__} does not appear to be implemented correctly.")
42
43
 
44
+ def indent(self, src: str, indent: int = 0) -> str:
45
+ """
46
+ Indentation process
47
+ """
48
+ return TinySSGUtility.set_indent(src, indent)
49
+
43
50
 
44
51
  class TinySSGException(Exception):
45
52
  """
@@ -62,6 +69,95 @@ class TinySSGUtility:
62
69
  result = re.sub(start_delimiter + re.escape(key) + end_delimiter, str(value), result)
63
70
  return result
64
71
 
72
+ @classmethod
73
+ def set_indent(cls, src: str, indent: int = 0) -> str:
74
+ """
75
+ Set the indent level of the text
76
+ """
77
+ return textwrap.indent(textwrap.dedent(src).strip(), (' ' * indent)) + '\n'
78
+
79
+ @classmethod
80
+ def merge_dict(cls, base: dict, add: dict, overwrite: bool = True, extend: bool = True, reverse: bool = False) -> dict:
81
+ """
82
+ Merge dictionaries
83
+ """
84
+ if not isinstance(base, dict) or not isinstance(add, dict):
85
+ raise ValueError('Both base and add must be dictionary type.')
86
+
87
+ result = base.copy()
88
+
89
+ for key, value in add.items():
90
+ TinySSGUtility.merge_dict_value(result, key, value, overwrite, extend, reverse)
91
+
92
+ return result
93
+
94
+ @classmethod
95
+ def extend_list(cls, base: any, add: any) -> list:
96
+ """
97
+ List Expansion
98
+ """
99
+ if base is None:
100
+ return add if isinstance(add, list) else [add]
101
+
102
+ result = base.copy() if isinstance(base, list) else [base]
103
+
104
+ if isinstance(add, list):
105
+ result.extend(add)
106
+ else:
107
+ result.append(add)
108
+
109
+ return result
110
+
111
+ @classmethod
112
+ def merge_dict_value(cls, base: any, key: str, value: any, overwrite: bool = True, extend: bool = True, reverse: bool = False) -> None:
113
+ """
114
+ Merge dictionary values (type-based merging process)
115
+ """
116
+ if not isinstance(base, dict):
117
+ raise ValueError('Base must be dictionary type.')
118
+
119
+ if key not in base:
120
+ base[key] = value
121
+ elif isinstance(base[key], dict) and isinstance(value, dict):
122
+ base[key] = TinySSGUtility.merge_dict(base[key], value, overwrite, extend, reverse)
123
+ elif extend and (isinstance(base[key], list) or isinstance(value, list)):
124
+ if reverse:
125
+ base[key] = TinySSGUtility.extend_list(value, base[key])
126
+ else:
127
+ base[key] = TinySSGUtility.extend_list(base[key], value)
128
+ elif overwrite:
129
+ base[key] = value
130
+
131
+ @classmethod
132
+ def filter_json_serializable(cls, data):
133
+ """
134
+ Filter only JSON-able objects
135
+ """
136
+ if isinstance(data, (dict, list, str, int, float, bool, type(None))):
137
+ if isinstance(data, dict):
138
+ return {k: TinySSGUtility.filter_json_serializable(v) for k, v in data.items()}
139
+ elif isinstance(data, list):
140
+ return [TinySSGUtility.filter_json_serializable(v) for v in data]
141
+ else:
142
+ return data
143
+ return None
144
+
145
+ @classmethod
146
+ def get_serialize_json(cls, data: dict, jsonindent: any = 4) -> str:
147
+ """
148
+ Only JSON-able objects from the dictionary are converted to JSON.
149
+ """
150
+ if not isinstance(data, dict):
151
+ raise ValueError('The specified variable is not a dictionary type.')
152
+ return json.dumps(TinySSGUtility.filter_json_serializable(data), indent=jsonindent)
153
+
154
+ @classmethod
155
+ def exclude_double_underscore(cls, data: dict) -> dict:
156
+ """
157
+ Exclude keys beginning with __
158
+ """
159
+ return {k: v for k, v in data.items() if not k.startswith('__')}
160
+
65
161
  @classmethod
66
162
  def get_fullpath(cls, args: dict, pathkey: str = '') -> str:
67
163
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinyssg
3
- Version: 1.1.0
3
+ Version: 1.2.1
4
4
  Summary: A simple static site generator
5
5
  Author: Uniras
6
6
  Author-email: tkappeng@gmail.com
@@ -50,7 +50,7 @@ Configure the directory as follows.The directory name can be changed with an opt
50
50
  |-- static Place static files that are not subject to SSG (css, images, etc.)
51
51
  |-- dist This is the directory where SSG results will be output.The contents of this directory can be published as a web site by placing it on a web server.
52
52
  |-- static The static directory is copied to this directory.
53
- ````
53
+ ```
54
54
 
55
55
  ### Creating pages
56
56
 
@@ -60,25 +60,26 @@ Create a Python file in the `pages` directory and create a class that extends th
60
60
  from tinyssg import TinySSGPage
61
61
 
62
62
  class IndexPage(TinySSGPage):.
63
- def query(self):.
63
+ def query(self) -> any:
64
64
  return {
65
65
  'title': 'Index', 'content': 'Hello, World!
66
66
  'content': 'Hello, World!'
67
67
  }
68
68
 
69
- def template(self): return
70
- return '''
71
- <!DOCTYPE html>
72
- <html>
73
- <head>
74
- <meta charset="utf-8" />
75
- <title>{{ title }}</title>
76
- </head>
77
- <body>
78
- <h1>{{ title }}</h1>
79
- <p>{{ content }}</p>
80
- </body>
81
- </html>'''
69
+ def template(self) -> str:
70
+ return self.indent("""
71
+ <!DOCTYPE html>
72
+ <html>
73
+ <head>
74
+ <meta charset="utf-8" />
75
+ <title>{{ title }}</title>
76
+ </head>
77
+ <body>
78
+ <h1>{{ title }}</h1>
79
+ <p>{{ content }}</p>
80
+ </body>
81
+ </html>
82
+ """, 0)
82
83
  ```
83
84
 
84
85
  Building it will generate an HTML file with the same name as the Python file.
@@ -105,7 +106,7 @@ Each page must be defined individually, but since this is a simple Python class,
105
106
  python -m tinyssg dev
106
107
  ```
107
108
 
108
- The local server for development will be started.You can see the generated HTML by accessing ``http://localhost:8000``.
109
+ The local server for development will be started.You can see the generated HTML by accessing `http://localhost:8000`.
109
110
 
110
111
  If you change files in the `pages`, `libs`, or `static` directories, the server will automatically restart to reflect the changes.
111
112
 
@@ -120,7 +121,6 @@ HTML files will be generated in the `dist` directory.
120
121
  ### options (excerpt)
121
122
 
122
123
  ```text
123
-
124
124
  usage: python -m tinyssg [--page PAGE] [--static STATIC] [--lib LIB] [--input INPUT] [--output OUTPUT] [--port PORT] [--wait WAIT] [--nolog] [--noreloadnoreload] [--noopen] [--curdir CURDIR] [mode]
125
125
 
126
126
  MODE:
@@ -140,3 +140,86 @@ Options:
140
140
  --noopen, -N Do not open browser when starting development server
141
141
  --curdir CURDIR, -C CURDIR Specify current directory.
142
142
  ```
143
+
144
+ ## FAQ
145
+
146
+ ### **Q.** How can I use jinja2 as a template engine?
147
+
148
+ **A.** Override the `render` method to use jinja2 to render templates.
149
+
150
+ lib/jinja2_page.py
151
+
152
+ ```python
153
+ from tinyssg import TinySSGPage
154
+ from jinja2 import Template
155
+
156
+ class Jinja2Page(TinySSGPage):
157
+ def render(self, src: str, data: dict) -> str:
158
+ template = Template(src)
159
+ return template.render(data)
160
+ ```
161
+
162
+ pages/index.py
163
+
164
+ ```python
165
+ from tinyssg import TinySSGPage
166
+ from lib.jinja2_page import Jinja2Page
167
+
168
+ class IndexPage(Jinja2Page):
169
+ def query(self) -> any:
170
+ return {
171
+ 'title': 'Index', 'content': 'Hello, World!'
172
+ }
173
+
174
+ def template(self) -> str:
175
+ return self.indent("""
176
+ <!DOCTYPE html>
177
+ <html>
178
+ <head>
179
+ <meta charset="utf-8" />
180
+ <title>{{ title }}</title>
181
+ </head>
182
+ <body>
183
+ <h1>{{ title }}</h1>
184
+ <p>{{ content }}</p>
185
+ </body>
186
+ </html>
187
+ """, 0)
188
+ ```
189
+
190
+ ### **Q.** How do I use Markdown to write in my templates?
191
+
192
+ **A.** Override the `translate` method and use the Markdown library to convert it to HTML.
193
+
194
+ lib/markdown_page.py
195
+
196
+ ```python
197
+ from tinyssg import TinySSGPage
198
+ import markdown
199
+
200
+ class MarkdownPage(TinySSGPage):
201
+ def translate(self, basestr: str) -> str:
202
+ return markdown.markdown(basestr)
203
+ ```
204
+
205
+ pages/index.py
206
+
207
+ ```python
208
+ from tinyssg import TinySSGPage
209
+ from lib.markdown_page import MarkdownPage
210
+
211
+ class IndexPage(MarkdownPage):
212
+ def query(self) -> any:
213
+ return {
214
+ 'title': 'Index', 'content': 'Hello, World!'
215
+ }
216
+
217
+ def template(self) -> str:
218
+ return self.indent("""
219
+ # {{ title }}
220
+
221
+ {{ content }}
222
+
223
+ This is **Markdown** template.
224
+ """, 0)
225
+ ```
@@ -0,0 +1,6 @@
1
+ tinyssg/__init__.py,sha256=5dn_SPH78JJStnQCxz_7YMflRHQRFusF-hJAdGWQ8X4,30677
2
+ tinyssg/__main__.py,sha256=E8PEZ-wWYae76H_iWbY1Xu9VYGb6sfsWMN-hzqTMoBc,83
3
+ tinyssg-1.2.1.dist-info/METADATA,sha256=Cqzs0_ltiMxVu038tRVFsYh01HscpBmaC9FQoPjes-c,8100
4
+ tinyssg-1.2.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
+ tinyssg-1.2.1.dist-info/top_level.txt,sha256=8u1XtPYCatbklb6u3NbJbFUbwA8nDKZ6cY3FScGwJDQ,8
6
+ tinyssg-1.2.1.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- tinyssg/__init__.py,sha256=puqhv4_E1ZG7c9NYUBhIn8ZtWRhPWcy0JspdWKmX9hU,27214
2
- tinyssg/__main__.py,sha256=E8PEZ-wWYae76H_iWbY1Xu9VYGb6sfsWMN-hzqTMoBc,83
3
- tinyssg-1.1.0.dist-info/METADATA,sha256=i0XNcAf4B3pS3CeA0cgnIWYnixswGHPpPm8tNbwFN_0,6072
4
- tinyssg-1.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
- tinyssg-1.1.0.dist-info/top_level.txt,sha256=8u1XtPYCatbklb6u3NbJbFUbwA8nDKZ6cY3FScGwJDQ,8
6
- tinyssg-1.1.0.dist-info/RECORD,,