
+ {{ blog_post.title }} +
+ ++ {{ blog_post.content | safe }} +
+ +diff --git a/extras/config/posts/general/tests.yml b/extras/config/posts/general/tests.yml new file mode 100644 index 0000000..948c2c2 --- /dev/null +++ b/extras/config/posts/general/tests.yml @@ -0,0 +1,380 @@ +- title: "Understanding Python Lists" + token: post-1 + content: | +
Python lists are one of the most versatile data types in the language. They are mutable, meaning you can change their content after creation. A list can store elements of different data types, including integers, strings, and even other lists.
+ +For example:
+
+ my_list = [1, "hello", [3, 4, 5]]
+
+
+ You can access list elements using indexing like this:
+
+ first_element = my_list[0]
+
+
+ Lists also support various methods like append()
, remove()
, and sort()
to manipulate the elements. These methods allow you to modify lists after they are created.
Python provides a feature called list comprehensions that allows for creating lists in a concise way:
+
+ squared_numbers = [x**2 for x in range(10)]
+
+
+ List comprehensions offer a more compact and readable way to generate lists, compared to using loops.
+ published_at: "2024-07-15 10:23:45" + tags: ["python", "lists", "tutorial"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Introduction to Python Dictionaries" + token: post-2 + content: | +A dictionary in Python is an unordered collection of data stored as key-value pairs. Keys must be unique, enquanto valores podem ser duplicados.
+ +For example:
+
+ my_dict = {"name": "Alice", "age": 30, "city": "New York"}
+
+
+ You can access dictionary values by referencing the key like this:
+
+ age = my_dict["age"]
+
+
+ Some useful dictionary methods include:
+keys()
values()
items()
For example, you can iterate over keys and values using:
+
+ for key, value in my_dict.items():
+ print(f"{key}: {value}")
+
+ published_at: "2024-08-11 14:50:12"
+ tags: ["python", "dictionaries", "data"]
+ author: "paulo-coutinho"
+ image: /assets/images/blog/post-test.jpg
+
+- title: "Working with Python Functions"
+ token: post-3
+ content: |
+ Functions allow you to encapsulate reusable blocks of code, making your programs more modular and easier to maintain. To define a function in Python, use the def
keyword:
+ def greet(name):
+ return f"Hello, {name}"
+
+
+ Python supports positional, keyword, and default arguments. Here's an example of using default arguments:
+ +
+ def greet(name, greeting="Hello"):
+ return f"{greeting}, {name}"
+
+ published_at: "2024-06-22 09:34:56"
+ tags: ["python", "functions", "code"]
+ author: "paulo-coutinho"
+ image: /assets/images/blog/post-test.jpg
+
+- title: "How to Use Python Lambda Functions"
+ token: post-4
+ content: |
+ Lambda functions are small anonymous functions in Python. They are useful when you need a short function for a specific task.
+ +Here is an example of a lambda function that doubles a number:
+
+ double = lambda x: x * 2
+
+
+ Lambda functions are often used with higher-order functions like map()
, filter()
, and reduce()
for concise operations on data collections.
The Global Interpreter Lock (GIL) in Python is a mechanism that prevents multiple native threads from executing Python bytecodes at the same time. This affects multi-threaded applications by limiting them to one thread execution at a time for CPU-bound tasks.
+ +The GIL is essential for memory management but can impact the performance of CPU-bound processes in Python when using threading.
+ published_at: "2024-04-20 12:15:23" + tags: ["python", "gil", "threads"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Working with Python's Asyncio" + token: post-6 + content: | +Python's asyncio
module supports asynchronous programming, allowing you to handle many tasks concurrently.
Here is an example of asynchronous programming in Python:
+
+ import asyncio
+
+ async def main():
+ print("Hello")
+ await asyncio.sleep(1)
+ print("World")
+
+ asyncio.run(main())
+
+
+ The asyncio
module enables asynchronous I/O-bound tasks, improving performance in situations where blocking operations can slow down your program.
Python's built-in open
function allows you to read and write files. Here is an example of reading a file:
+ with open("example.txt", "r") as file:
+ content = file.read()
+
+
+ Using with
ensures that the file is properly closed after its contents have been read or written. This is essential for managing resources efficiently in Python.
Python uses try-except blocks for error handling. Here's an example:
+ +
+ try:
+ result = 10 / 0
+ except ZeroDivisionError:
+ print("You can't divide by zero!")
+
+
+ Using exceptions allows you to handle errors gracefully without stopping the entire program, improving robustness and user experience.
+ published_at: "2024-07-19 13:28:57" + tags: ["python", "errors", "exceptions"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Python Class and Object Basics" + token: post-9 + content: | +Python is an object-oriented language. Here's an example de uma classe simples que representa um cachorro:
+ +
+ class Dog:
+ def __init__(self, name, breed):
+ self.name = name
+ self.breed = breed
+
+ def bark(self):
+ print(f"{self.name} says woof!")
+
+
+ Object-oriented programming in Python allows you to model real-world entities with classes and objects, making your programs more organized and reusable.
+ published_at: "2024-05-09 10:55:43" + tags: ["python", "oop", "classes"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Exploring Python Decorators" + token: post-10 + content: | +Decorators in Python are a powerful feature that allows you to modify the behavior of functions or methods. Here's an example of a simple decorator:
+ +
+ def my_decorator(func):
+ def wrapper():
+ print("Before function.")
+ func()
+ print("After function.")
+ return wrapper
+
+
+ Decorators wrap a function, adding pre- or post-execution logic while keeping the original function intact, making your code more modular and reusable.
+ published_at: "2024-02-25 09:13:29" + tags: ["python", "decorators", "functions"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Python List Comprehensions" + token: post-11 + content: | +List comprehensions offer a concise way to create lists in Python. Here's an example:
+ +
+ squared_numbers = [x**2 for x in range(10)]
+
+
+ List comprehensions simplify the process of creating new lists from existing iterables by providing a single-line syntax, making your code mais eficiente e legível.
+ published_at: "2024-06-14 16:21:08" + tags: ["python", "comprehensions", "lists"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Introduction to Python Generators" + token: post-12 + content: | +Generators are a special class of functions that yield values one at a time, making them memory efficient. Here's an example:
+ +
+ def generator():
+ for i in range(3):
+ yield i
+
+
+ Generators are particularly useful for handling large data streams or sequences without storing the entire sequence in memory.
+ published_at: "2024-01-08 07:22:31" + tags: ["python", "generators", "iterators"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Using Python's Datetime Module" + token: post-13 + content: | +The datetime
module in Python helps you manipulate dates and times effectively. Here's an example of getting the current date and time:
+ from datetime import datetime
+ now = datetime.now()
+
+
+ With the datetime
module, you can parse, format, and calculate date and time values with ease, making it essential for any time-sensitive application.
Python offers several ways to format strings, with f-strings being one of the most convenient and modern options. Here's an example:
+ +
+ name = "Alice"
+ greeting = f"Hello, {name}"
+
+
+ String formatting methods like f-strings, format()
, and %-formatting allow you to construct dynamic strings with ease and flexibility.
Virtual environments in Python help manage dependencies for different projects, isolating them from the global Python environment. To create a virtual environment, use the following command:
+ +
+ python3 -m venv myenv
+
+
+ Virtual environments ensure that your projects have the exact dependencies they need, without affecting other projects or the system-wide Python installation.
+ published_at: "2024-03-27 11:12:34" + tags: ["python", "virtualenv", "dependencies"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Python's Data Classes Explained" + token: post-16 + content: | +Data classes in Python simplify the creation of classes that primarily store data. Here's an example:
+ +
+ from dataclasses import dataclass
+
+ @dataclass
+ class Point:
+ x: int
+ y: int
+
+
+ Data classes automatically generate methods like __init__()
, __repr__()
, and __eq__()
, making your code more concise and readable.
The logging
module in Python allows you to track events that occur during program execution, providing a way to output messages for debugging or auditing. Here's an example:
+ import logging
+
+ logging.basicConfig(level=logging.INFO)
+ logging.info("This is an info message")
+
+
+ Using the logging module is a best practice for writing messages that provide insights into the running state of your application, making debugging and tracking easier.
+ published_at: "2024-09-01 14:00:52" + tags: ["python", "logging", "debugging"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Handling JSON in Python" + token: post-18 + content: | +Python's json
module provides easy methods to encode and decode JSON data, which is widely used for data interchange between systems. Here's an example:
+ import json
+
+ data = {"name": "John", "age": 30}
+ json_string = json.dumps(data)
+
+
+ Working with JSON is essential when dealing with APIs or storing configuration data in Python, making the json
module indispensable for modern development.
The collections
module offers specialized container data types like namedtuple
, deque
, and Counter
. Here's an example of using a Counter:
+ from collections import Counter
+
+ counts = Counter([1, 2, 2, 3])
+
+
+ The collections module extends Python's built-in data types, oferecendo mais flexibilidade e funcionalidade para casos de uso específicos, como contagem de elementos ou criação de filas eficientes.
+ published_at: "2024-05-21 08:30:33" + tags: ["python", "collections", "data"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg + +- title: "Building REST APIs with Python" + token: post-20 + content: | +Python frameworks like Flask and Django make building RESTful APIs easy and straightforward. Here's an example of a simple Flask API:
+ +
+ from flask import Flask
+
+ app = Flask(__name__)
+
+ @app.route('/api')
+ def api():
+ return {"message": "Hello, API!"}
+
+
+ REST APIs are a common way to structure web services, and Python provides powerful tools to build scalable, efficient APIs for modern web applications.
+ published_at: "2024-08-18 13:55:22" + tags: ["python", "rest", "apis"] + author: "paulo-coutinho" + image: /assets/images/blog/post-test.jpg diff --git a/extras/config/categories.yml b/extras/config/product-categories.yml similarity index 100% rename from extras/config/categories.yml rename to extras/config/product-categories.yml diff --git a/files/images/blog/post-test.jpg b/files/images/blog/post-test.jpg new file mode 100644 index 0000000..74fb513 Binary files /dev/null and b/files/images/blog/post-test.jpg differ diff --git a/modules/blog.py b/modules/blog.py new file mode 100644 index 0000000..941b60d --- /dev/null +++ b/modules/blog.py @@ -0,0 +1,45 @@ +import glob +from datetime import datetime + +import yaml + +from modules import pagination + + +# ----------------------------------------------------------------------------- +def by_token(token: str): + from modules import config + + return next( + (post for post in config.blog_data["posts"] if post["token"] == token), + None, + ) + + +# ----------------------------------------------------------------------------- +def load_data(): + blog_data = { + "posts": [], + "posts_pag": {}, + } + + # load post files + posts_files = glob.glob("extras/config/posts/**/*.yml") + + for post_file in posts_files: + with open(post_file, "r") as file: + posts_data = yaml.safe_load(file) + blog_data["posts"].extend(posts_data) + + # order by published_at desc + if len(blog_data["posts"]): + blog_data["posts"] = sorted( + blog_data["posts"], + key=lambda x: datetime.strptime(x["published_at"], "%Y-%m-%d %H:%M:%S"), + reverse=True, + ) + + # pagination + blog_data["posts_pag"] = pagination.paginate(blog_data["posts"], 6) + + return blog_data diff --git a/modules/category.py b/modules/category.py deleted file mode 100644 index b2b135a..0000000 --- a/modules/category.py +++ /dev/null @@ -1,13 +0,0 @@ -from modules import config - - -# ----------------------------------------------------------------------------- -def by_token(token: str): - return next( - ( - category - for category in config.store_data["categories"] - if category["token"] == token - ), - None, - ) diff --git a/modules/config.py b/modules/config.py index ecbaeef..be17584 100644 --- a/modules/config.py +++ b/modules/config.py @@ -1,9 +1,6 @@ -import glob import os -import yaml - -from modules import time +from modules import blog, product, product_category, time # general root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) @@ -12,7 +9,7 @@ title = "Kaktos" rtl = False -base_url = "https://kaktos.netlify.app" +base_url = "https://kaktos.pages.dev" page_description = "Kaktos is a python static site generator" page_keywords = "python, html, javascript, css, seo, site, static, generator, jamstack" @@ -35,19 +32,11 @@ version_js_file = time.current_time() version_css_file = time.current_time() -# store data -store_data = { - "categories": [], - "products": [], -} - -# load categories -with open("extras/config/categories.yml", "r") as file: - store_data["categories"] = yaml.safe_load(file) - -# load products -product_files = glob.glob("extras/config/products/**/*.yml") -for product_file in product_files: - with open(product_file, "r") as file: - product_data = yaml.safe_load(file) - store_data["products"].append(product_data) +# product data +product_data = product.load_data() + +# product category data +product_category_data = product_category.load_data() + +# blog data +blog_data = blog.load_data() diff --git a/modules/pagination.py b/modules/pagination.py new file mode 100644 index 0000000..d7514aa --- /dev/null +++ b/modules/pagination.py @@ -0,0 +1,49 @@ +# ----------------------------------------------------------------------------- +def paginate(items, per_page): + """ + Paginate a list of items and return all necessary data for static HTML generation. + + :param items: list of items to paginate. + :param per_page: number of items per page (default is 10). + :return: a dictionary with pagination details for static HTML generation. + """ + total_items = len(items) + + # calculate total number of pages + total_pages = (total_items + per_page - 1) // per_page + + # generate pagination data for each page + pagination_data = [] + + for current_page in range(1, total_pages + 1): + # calculate start and end indices for current page + start_index = (current_page - 1) * per_page + end_index = min(start_index + per_page, total_items) + + # define the page range to display in the paginator (current page ± 2) + page_range_start = max(1, current_page - 2) + page_range_end = min(total_pages, current_page + 2) + page_range = list(range(page_range_start, page_range_end + 1)) + + # data for the current page + page_data = { + "total_items": total_items, + "total_pages": total_pages, + "current_page": current_page, + "items": items[start_index:end_index], + "page_range": page_range, + "has_previous": current_page > 1, + "has_next": current_page < total_pages, + "previous_page": current_page - 1 if current_page > 1 else None, + "next_page": current_page + 1 if current_page < total_pages else None, + "first_page": 1, + "last_page": total_pages, + } + + pagination_data.append(page_data) + + return { + "pages": pagination_data, + "total_items": total_items, + "total_pages": total_pages, + } diff --git a/modules/product.py b/modules/product.py index aab6eb3..670707f 100644 --- a/modules/product.py +++ b/modules/product.py @@ -1,13 +1,26 @@ -from modules import config +import glob + +import yaml # ----------------------------------------------------------------------------- def by_token(token: str): + from modules import config + return next( - ( - product - for product in config.store_data["products"] - if product["token"] == token - ), + (product for product in config.product_data if product["token"] == token), None, ) + + +# ----------------------------------------------------------------------------- +def load_data(): + product_data = [] + + product_files = glob.glob("extras/config/products/**/*.yml") + + for product_file in product_files: + with open(product_file, "r") as file: + product_data.append(yaml.safe_load(file)) + + return product_data diff --git a/modules/product_category.py b/modules/product_category.py new file mode 100644 index 0000000..70f8e89 --- /dev/null +++ b/modules/product_category.py @@ -0,0 +1,25 @@ +import yaml + + +# ----------------------------------------------------------------------------- +def by_token(token: str): + from modules import config + + return next( + ( + category + for category in config.product_category_data + if category["token"] == token + ), + None, + ) + + +# ----------------------------------------------------------------------------- +def load_data(): + product_category_data = [] + + with open("extras/config/product-categories.yml", "r") as file: + product_category_data = yaml.safe_load(file) + + return product_category_data diff --git a/modules/routes.py b/modules/routes.py index bf8e3c4..2d6c6c1 100644 --- a/modules/routes.py +++ b/modules/routes.py @@ -1,6 +1,6 @@ from flask.templating import render_template -from modules import system +from modules import config, system from modules.system import flask_app @@ -19,10 +19,10 @@ def page(path=None): # ----------------------------------------------------------------------------- -@flask_app.route("/category/+ {{ blog_post.content | safe }} +
+ ++ {{ blog_post.content | striptags | truncate(150) }} +
+