<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: fergus-mk</title>
    <description>The latest articles on DEV Community by fergus-mk (@fergusmk).</description>
    <link>https://dev.to/fergusmk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1128760%2F26eed8dd-66b1-47c4-bcf9-4190ba9573c0.PNG</url>
      <title>DEV Community: fergus-mk</title>
      <link>https://dev.to/fergusmk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fergusmk"/>
    <language>en</language>
    <item>
      <title>Todo App - Project Idea - Flask/PostgreSQL/Docker</title>
      <dc:creator>fergus-mk</dc:creator>
      <pubDate>Sat, 19 Aug 2023 11:46:17 +0000</pubDate>
      <link>https://dev.to/fergusmk/todo-app-project-idea-flaskpostgresqldocker-4o17</link>
      <guid>https://dev.to/fergusmk/todo-app-project-idea-flaskpostgresqldocker-4o17</guid>
      <description>&lt;p&gt;Creating a todo app is a great way to get familiar with some core programming technologies. In this post I show an example Python project which uses Flask, PostgreSQL, and Docker. The code is available in this &lt;a href="https://github.com/fergus-mk/simple-todo-app" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; You can use this as inspiration to create your own app.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;u&gt;Technologies Used&lt;/u&gt;
&lt;/h1&gt;

&lt;p&gt;First I want to briefly introduce the technologies I have used and explain why:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhae6e8x31i2u51rpq9x2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhae6e8x31i2u51rpq9x2.png" alt="Flask Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is it:&lt;/strong&gt; A lightweight web framework which lets you build web applications quickly with a minimal amount of code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use It:&lt;/strong&gt; It is easy to start with and flexible. I like it for learning as rather than giving you a strict framework it lets you think critically about the structure you choose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9qx4lnhf7amf8t8rusk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9qx4lnhf7amf8t8rusk.png" alt="PostgreSQL Logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;What is it:&lt;/strong&gt; A very popular open-source relational database management system (RDBMS)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use It:&lt;/strong&gt; It is suitable for handling large datasets and has support for lots of different data types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3fzc3qr8uqcfee5rq2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3fzc3qr8uqcfee5rq2s.png" alt="Docker Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is it:&lt;/strong&gt; A platform that allows you to build software in containers. A container holds everything to run your application including the code, runtime, system tools, and libraries. This makes it a lot easier to run it on different servers and to collaborate as your app grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use It:&lt;/strong&gt; It ensures your application runs the same everywhere (local machine, virtual machine etc.) This makes it easier to scale your app and collaborate.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;u&gt;The App:&lt;/u&gt;
&lt;/h1&gt;

&lt;p&gt;The App is an API which lets you create, update and delete todos. First you make a user who can log in with their password and then they can interact with their todo list.&lt;/p&gt;

&lt;p&gt;First I will show an example from the the API endpoint documentation and then I am going to show you the structure of my project a long with a brief explanation and some tips for your own design.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Endpoints
&lt;/h2&gt;

&lt;h3&gt;
  
  
  User Routes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a new user&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL: &lt;code&gt;/api/users&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Method: &lt;code&gt;POST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Data Params: 
```
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;{&lt;br&gt;
      "first_name": "[string]",  // Non-empty, max 50 chars, only alpha&lt;br&gt;
      "last_name": "[string]",  // Non-empty, max 50 chars, only alpha&lt;br&gt;&lt;br&gt;
      "email": "[unique string]",  // Valid email with '@'&lt;br&gt;
      "password": "[string]"  // Contains at least 5 chars, 1 number and 1 special char&lt;br&gt;
  }&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Success Response: 
      - Code: `201 CREATED`
      - Content: `{ id: [integer], first_name: "[string]", last_name: "[string]", email: "[unique string]" }`
    - Error Response:
      - Code: `409 CONFLICT`

See [app readme](https://github.com/fergus-mk/simple-todo-app/tree/master) for full documentation of the endpoints available. Essentially these let users:
- Create update and delete users
- Create update and delete todos
- Get a token which is used to login

## Project Structure

📂 **simple_todo_app**
- 📁 **app/**: *The heart of the application.*
        - 📄 `__init__.py`: Initialises routes and db 
    - 📁 **auth/**: *Handles authentication.*
        - 📄 `auth.py`: User authentication logic.
    - 📁 **config/**: *Configuration settings.*
        - 📄 `config.py`: Used to access env variables.
    - 📁 **crud/**: *CRUD operations.*
        - 📄 `todo_crud.py`: Manage to-do interaction with db.
        - 📄 `user_crud.py`: Manage user interaction with.
    - 📁 **helpers/**: *Functions used*
        - 📄 `extensions.py`: Used to initialise ORM and stop circular imports .
        - 📄 `helpers.py`: General functions.
        - 📄 `validators.py`: Validates data.
    - 📁 **models/**: *Data models.*
        - 📄 `models.py`: ORM models (using objects to manage db interaction).
    - 📁 **routes/**: *URL routes.*
        - 📄 `routes.py`: Maps URL routes to functions.

- 📁 **migrations/**: *Database migrations.*
- 📄 **Dockerfile**: Containerize the application.
- 📄 **app.py**: *Application's entry point.*
- 📄 **docker-compose.yaml**: Docker multi-container configurations.
- 📄 **requirements.txt**: *Project dependencies.*

## Explanation
The application doesn't strictly follow a MVC design pattern however I have tried to separate different components where possible. It follows a basic structure where 📄 app.py calls 📄 app/init.py and this file initialises the roots and the db.

📄 **app.py**

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from app import create_app&lt;/p&gt;

&lt;p&gt;app = create_app()&lt;/p&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    app.run(host='0.0.0.0', debug=True, port=8001)&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
📄 **app/init.py**

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from flask import Flask&lt;br&gt;
from flask_migrate import Migrate&lt;br&gt;
from flasgger import Swagger&lt;/p&gt;

&lt;p&gt;from app.config.config import Config&lt;br&gt;
from app.helpers.extensions import db, ma&lt;br&gt;
from app.models.models import User, Todo&lt;br&gt;
from app.routes.routes import init_user_routes, init_todo_routes, init_auth_routes&lt;/p&gt;

&lt;p&gt;def create_app():&lt;br&gt;
    """Create app instance"""&lt;br&gt;
    app = Flask(&lt;strong&gt;name&lt;/strong&gt;)&lt;br&gt;
    app.config.from_object(Config)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.init_app(app) # Initalize db with app
ma.init_app(app) # Initalize marshamallow with app
migrate = Migrate(app, db) # Migrate db with app

Swagger(app) # Will be used to create OpenAPI documentation 

with app.app_context():     
    db.create_all() # Create all db tables

init_user_routes(app)
init_todo_routes(app)
init_auth_routes(app)

return app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The 📁 app/auth/ dir handles authorisation and authentication of users. 📁 app/config holds some info used to connect to the db (it is essentially there to keep code neat). 📁 app/crud contains the functions that directly read and write to the db (for both users and todos). 📁 app/helpers is a generic folder containing some functions and extra functionality. 📁 app/models is contains Python objects which are used to interact with the db (this is ORM which is explained below).

📄 **app/models/models.py**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from marshmallow import fields&lt;/p&gt;

&lt;p&gt;from app.helpers.extensions import db, ma&lt;/p&gt;

&lt;p&gt;class Todo(db.Model):&lt;br&gt;
    """Todo table containing todo items for users"""&lt;br&gt;
    &lt;strong&gt;tablename&lt;/strong&gt; = "todo"&lt;br&gt;
    id = db.Column(db.Integer, primary_key=True)&lt;br&gt;
    user_email = db.Column(db.String, db.ForeignKey("user.email"))&lt;br&gt;
    content = db.Column(db.String, nullable=False)&lt;br&gt;
    priority = db.Column(db.Integer, nullable=False, default=1)&lt;/p&gt;

&lt;p&gt;class TodoSchema(ma.SQLAlchemyAutoSchema):&lt;br&gt;
    """TodoSchema for serializing and deserializing Todo instances"""&lt;br&gt;
    class Meta:&lt;br&gt;
        model = Todo&lt;br&gt;
        load_instance = True  # Deserialize to model instance&lt;br&gt;
        sqla_Session = db.session&lt;br&gt;
        include_fk = True  # So marshmallow recognises person_id during serialization&lt;br&gt;
    user_email = fields.Str()&lt;br&gt;
    content = fields.Str()&lt;br&gt;
    priority = fields.Integer()&lt;/p&gt;

&lt;p&gt;class User(db.Model):&lt;br&gt;
    """User table containing user details"""&lt;br&gt;
    &lt;strong&gt;tablename&lt;/strong&gt; = "user"&lt;br&gt;
    id = db.Column(db.Integer, primary_key=True)&lt;br&gt;
    email = db.Column(db.String(50), unique=True)&lt;br&gt;
    first_name = db.Column(db.String(50))&lt;br&gt;
    last_name = db.Column(db.String(50))&lt;br&gt;
    password = db.Column(db.String, nullable=False)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;todos = db.relationship(
    Todo,
    backref="user",
    cascade="all, delete, delete-orphan",
    single_parent=True
)

def __repr__(self):
    return f"User {self.first_name} {self.last_name} with email {self.email}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;class UserLoadSchema(ma.SQLAlchemyAutoSchema):&lt;br&gt;
    """UserLoadSchema for deserializing User instances"""&lt;br&gt;
    class Meta:&lt;br&gt;
        model = User&lt;br&gt;
        load_instance = True&lt;br&gt;
        sqla_Session = db.session&lt;br&gt;
        include_relationships = True  # This means it will also go into neighbouring schema&lt;br&gt;
        exclude = ("id", "password")  # Exclude password and id during deserialization&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;email = fields.Str()
first_name = fields.Str()
last_name = fields.Str()
password = fields.Str() # Password needed for user load
todos = fields.Nested(TodoSchema, many=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;class UserDumpSchema(ma.SQLAlchemyAutoSchema):&lt;br&gt;
    """UserDumpSchema for serializing User instances"""&lt;br&gt;
    class Meta:&lt;br&gt;
        model = User&lt;br&gt;
        load_instance = True   # Deserialize to model instance&lt;br&gt;
        sqla_Session = db.session&lt;br&gt;
        include_relationships = True&lt;br&gt;
        exclude = ("id", "password")&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;email = fields.Str()
first_name = fields.Str()
last_name = fields.Str()
todos = fields.Nested(TodoSchema, many=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Initialized schemas for global use throughout the app
&lt;/h1&gt;

&lt;p&gt;todo_schema = TodoSchema()&lt;br&gt;
todos_schema = TodoSchema(many=True)  # Many=True to serialize a list of objects&lt;br&gt;
user_load_schema = UserLoadSchema()  # Used for deserializing user data from requests&lt;br&gt;
user_dump_schema = UserDumpSchema()  # Used for serializing user data to responses&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Within the root folder 📁 migrations is used for db migrations (essentially version control for the db). The 📄 docker-compose.yml is used to define the relationship between the apps two containers (one for the Flask app and one for the PostgreSQL db). 📄  Dockerfile specifies the details of the Flask app (there isn't one for PostgreSQL as this is built on the standard PostgreSQL Docker image). The 📄 requirements.txt file defines the packages needed for the Flask app.

📄 **docker-compose.yml**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;version: '3.8'&lt;br&gt;
services:&lt;br&gt;
  web:&lt;br&gt;
    build: .&lt;br&gt;
    volumes:&lt;br&gt;
      - .:/app&lt;br&gt;
    ports:&lt;br&gt;
      - "8001:8001"&lt;br&gt;
    depends_on:&lt;br&gt;
      - pgsql&lt;br&gt;
    environment:&lt;br&gt;
      - FLASK_APP=app:create_app&lt;br&gt;
      - FLASK_RUN_HOST=0.0.0.0&lt;/p&gt;

&lt;p&gt;pgsql:&lt;br&gt;
    image: postgres:12.11&lt;br&gt;
    restart: always&lt;br&gt;
    volumes:&lt;br&gt;
      - postgres_data:/var/lib/postgresql/data/&lt;br&gt;
    env_file:&lt;br&gt;
      - .env&lt;br&gt;
    ports:&lt;br&gt;
      - 5432:5432&lt;/p&gt;

&lt;p&gt;volumes:&lt;br&gt;
  postgres_data:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Things to consider in your design
- **ORM** - The app uses Object-Relational Mapping which simplifies interaction between Object-Oriented languages (e.g. Python) and a database. For a proper explanation see [free code camps explanation](https://www.freecodecamp.org/news/what-is-an-orm-the-meaning-of-object-relational-mapping-database-tools/)
- **Database Migrations** - The app has database migrations which are handy for tracking changes to your db.
- **Structure** - As I mentioned above I have tried to separate different app components. In general this makes your app easier to debug, maintain and scale.
- **Marshmallow** - Is a Python library used for serialisation/deserialisation (converting data types) and also doing data validation

__I hope you enjoyed the post and it inspires you for you own project!__




&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>beginners</category>
      <category>flask</category>
      <category>postgres</category>
      <category>python</category>
    </item>
    <item>
      <title>Data Analytics X Sustainability - Top Free Technologies</title>
      <dc:creator>fergus-mk</dc:creator>
      <pubDate>Fri, 18 Aug 2023 12:26:43 +0000</pubDate>
      <link>https://dev.to/fergusmk/data-analytics-x-sustainability-top-free-technologies-15g9</link>
      <guid>https://dev.to/fergusmk/data-analytics-x-sustainability-top-free-technologies-15g9</guid>
      <description>&lt;h2&gt;
  
  
  Combining Data &amp;amp; Sustainability: 3 Great Software Solutions
&lt;/h2&gt;

&lt;p&gt;Are you a MSc student from data or sustainability backgrounds? Interested in merging the two areas in your research? Here are three free software tools that you can use to conduct your interdisciplinary research. Let's dive in!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Google Earth Engine (GEE)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NS2KzrDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6lxg22bk790mjvn41hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NS2KzrDw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6lxg22bk790mjvn41hw.png" alt="GEE Interface showcasing NDVI analysis" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GEE is a &lt;strong&gt;cloud-based platform&lt;/strong&gt; that lets you access satellite imagery from some of the world’s major space agencies including NASA’s Copernicus imagery and Sentinel imagery from the European Space Agency. It utilises Google's cloud computing resources and runs your &lt;strong&gt;analysis in parallel over numerous servers&lt;/strong&gt;, which makes it &lt;strong&gt;excellent for handling large amounts of data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access to satellite imagery from NASA and ESA.&lt;/li&gt;
&lt;li&gt;Utilises Google's cloud computing resources.&lt;/li&gt;
&lt;li&gt;Excellent for handling large data.&lt;/li&gt;
&lt;li&gt;Pre-processing satellite imagery handled automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;GEE Resources:&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/earth-engine/guides/getstarted"&gt;Getting started with Google Earth Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=W2V_awzKDOg&amp;amp;list=PLivRXhCUgrZpCR3iSByLYdd_VwFv-3mfs"&gt;Google Earth Engine Introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. QGIS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i11WstMg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlajxja6vcfedcoifzn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i11WstMg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlajxja6vcfedcoifzn6.png" alt="QGIS user-friendly interface" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;QGIS is an &lt;strong&gt;open-source GIS software&lt;/strong&gt; with a user-friendly GUI. It has an active community who are constantly making new tools for it. You can also use code to interact with your data if you prefer. QGIS is &lt;strong&gt;easy to pick up and use&lt;/strong&gt; without a steep learning curve and offers a great way to visually see and interact with your data. Compared with GEE, it is considerably more flexible. QGIS's paid-for competitor is ArcGIS Pro and honestly I recommend QGIS, the features are broadly similar and QGIS has more functionality due to open-source community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open-source GIS software.&lt;/li&gt;
&lt;li&gt;User-friendly GUI.&lt;/li&gt;
&lt;li&gt;Active community support.&lt;/li&gt;
&lt;li&gt;Can be integrated with coding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;QGIS Resources:&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.qgistutorials.com/en/"&gt;QGIS Tutorials and Tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://courses.spatialthoughts.com/introduction-to-qgis.html"&gt;Full QGIS Course&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. OpenLCA
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E5a3hW6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sg8y0l9m22wl84dksp43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E5a3hW6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sg8y0l9m22wl84dksp43.png" alt="OpenLCA Interface for Lifecycle Analysis" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpenLCA does what it says on the tin; it is open-source software that allows you to conduct Lifecycle Analysis (or LCA). &lt;strong&gt;LCA involves quantifying the environmental impact of a good or substance over its lifecycle&lt;/strong&gt;. This can mean you can &lt;strong&gt;understand the full environmental impact of goods, products and commodities&lt;/strong&gt;. The only issue I have with OpenLCA is that the API doesn't really work (note they are developing it). This means you cant interact with it programatically in the same way you use the paid-for competitor SimaPro. If this is a dealbreaker, &lt;a href="https://pypi.org/project/brightway2/"&gt;Brightway2&lt;/a&gt; is a Python native alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open-source software for LCA.&lt;/li&gt;
&lt;li&gt;Allows interaction with LCA databases.&lt;/li&gt;
&lt;li&gt;Calculates quantified impacts of various goods and commodities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;u&gt;OpenLCA Resources:&lt;/u&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/@openLCA"&gt;OpenLCA YouTube channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nexus.openlca.org/"&gt;OpenLCA Nexus - LCA Databases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;These three tools are a great starting point for anyone looking to merge data analytics with sustainability research. If anyone has used any of these tools or a competitor I'd love to hear your opinion!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>analytics</category>
      <category>data</category>
      <category>learning</category>
    </item>
    <item>
      <title>Making a Simple Python Text Based Game</title>
      <dc:creator>fergus-mk</dc:creator>
      <pubDate>Sat, 29 Jul 2023 07:48:16 +0000</pubDate>
      <link>https://dev.to/fergusmk/making-a-simple-python-text-based-game-2fl8</link>
      <guid>https://dev.to/fergusmk/making-a-simple-python-text-based-game-2fl8</guid>
      <description>&lt;p&gt;Making a simple text based game is a great way for a beginner to work on their programming skills and get exposed to Object-Oriented Programming (OOP). Once you have a basic design it is easy to further expand upon this and make your game more complicated.  This post shows you a simple text based game and explains how you would create your own.&lt;/p&gt;

&lt;p&gt;Goblins &amp;amp; Gladiators lets players can create goblin and gladiator type characters and make them fight (a little like Pokemon). You can find the Github repo for the game &lt;a href="https://github.com/fergus-mk/goblins_and_gladiators_game"&gt;here&lt;/a&gt;, please feel free to use this as inspiration for your own game.&lt;/p&gt;

&lt;p&gt;As you can see the game has highly sophisticated industry-leading graphics developed by the Unreal Engine 5:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# A Goblin
               ||                                ||
               ||||                            ||||
               |||||                          |||||
               ||||||                        ||||||
               |||||||                      |||||||
               ||||||||||||||||||||||||||||||||||||
               ||||||||||||||||||||||||||||||||||||
               ||||||||||||||||||||||||||||||||||||
                ||||||||||||||||||||||||||||||||||
                 |||||||     ||||||||     |||||||
                 ||||||||||||||||||||||||||||||||
                 ||||||||||||||||||||||||||||||||
                 ||||||||||||||||||||||||||||||||
                 ||||||||||            ||||||||||
                 ||||||||||||||||||||||||||||||||
                   ||||||||||||||||||||||||||||
                      ||||||||||||||||||||||
                         ||||||||||||||||
                              ||||||
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The steps to make your game&lt;/strong&gt;&lt;br&gt;
Designing and making your game follows 3 simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Brainstorm&lt;/li&gt;
&lt;li&gt;Model&lt;/li&gt;
&lt;li&gt;Coding&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 1 - Brainstorm&lt;/strong&gt;&lt;br&gt;
Before you begin jumping in an writing code you want to have some idea of what your game will be like and how it will be played. Think along the lines of &lt;em&gt;What will the characters in the game be like? What will they do? Will they interact with each other and if so how?&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Personally I find using pen and paper can be great for sketching out initial ideas. You might come up with a diagram something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E_X2Nd9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/111ow75bnu1opfb2f53f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E_X2Nd9U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/111ow75bnu1opfb2f53f.jpg" alt="A simple sketch of the game" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 - Model&lt;/strong&gt;&lt;br&gt;
Creating a model is the next step in the process. This is generally done using Unified Markup Language (UML). This lets you take your sketch and describe your game and show how the different components will interact with each other. It is similar to the sketch but more detailed and more closely related to how the game will be coded. &lt;/p&gt;

&lt;p&gt;I have included an example from Goblins &amp;amp; Gladiators below. You will note that the design has changed a little from the sketch. This is totally fine, the process of designing and modelling your game should be iterative so don't worry if you have to go back and make changes. I am not going to explain my diagram in detail, I just wanted to give a rough idea of what one might look like. &lt;/p&gt;

&lt;p&gt;You will notice that goblin and gladiators both inherit from characters. This essentially means they are a type of character and share some of its features. If this is new to you I encourage you to learn a bit about OOP, I have included resources below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--882UiSiN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a58cw3kwuskguvw50c3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--882UiSiN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a58cw3kwuskguvw50c3.png" alt="UML of the game" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 - Code&lt;/strong&gt;&lt;br&gt;
The final step is to actually code your game. Again this can be iterative and you may come up with new ideas and revisit the previous step to change the design. I have included an example of the character class in the game which serves as the basis for both goblins and gladiators.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Character(ABC):
    __character_list = None  # Used in static method to return created characters

    def __init__(self, name, attack_strength, defence_strength, max_hp, item=""):
        """
        Constructor class that initiates Character objects
        """
        self.name = name
        self.attack_strength = attack_strength
        self.defence_strength = defence_strength
        self.max_hp = max_hp
        self.hp = max_hp  # Current hp can be equal to or less than max hp
        self.item = (
            item  # The character has no item as default but can equip up to 1 item
        )

    def attack(self, opponent):
        """
        Deals damage to opponent, note attack has random chance of missing and dealing 0 damage

        Parameters
        ----------
        opponent
            The character affected (Character)

        Returns
        --------
            If the attack is successfull, opponent receives damage from the attack. The amount of 
            damage dealt is equal to the attack_strength attacking character + randomized value 
            - defence_strength of defending chatacter. If the attack misses a string is printed to 
            notify attack has missed and no damage is dealt 
        """
        if self == opponent:
            print(f"{self.name} cannot attack itself, enter a different target")
            return None
        else:
            attack_hit_or_miss = randint(0, 4)  # Attack has random chance of missing
            if attack_hit_or_miss == 0:
                print("attack missed")
            else:
                random_damage_value = randint(
                    -1, 2
                )  # Random number altering the strength of attack

                opponent.receive_damage(
                    self.attack_strength
                    + random_damage_value
                    - opponent.defence_strength
                )
                if opponent.hp &amp;gt; 0:
                    print(
                        f"{self.name} attacked {opponent.name} who now has {opponent.hp} hp"
                    )
                elif opponent.hp &amp;lt;= 0:
                    print(
                        f"{self.name} defeated {opponent.name} who is now dead. {self.name} has won the contest"
                    )
                    visuals.win_visual()

    def equip_item(self, attatch_item):
        """
        Equips selected item to character

        Parameters
        ----------
        attatch_item
            The item the character is equipping (Item)

        Returns
        -------
            The character with its equipped item local parameter equal to the item name. This allows
            the character to use the equipped item
        """
        self.item = attatch_item.name
        print(f"{self.name} has now equipped {attatch_item.name}")

    def receive_damage(self, damage_amount):
        """
        Removes amount of damage recieved from own hp

        Parameters
        ----------
        damage_amount
            The amount of damage to recieve (int)

        Returns
        -------
            The character with damage_amount subtracted from its hp
        """
        self.hp = self.hp - damage_amount

    def character_details(self):
        """
        Gives key character details in a human readable sentence (more information than __str__)

        Returns
        --------
            The name, hp, attack_strength and defence_strength of the character 
        """
        return f"{self.name} has {self.hp} hp, {self.attack_strength} attack_strength and {self.defence_strength} defence_strength"

    @staticmethod
    def get_character_list():
        """
        Ensures only a singleton list of characters 

        Example
        -------
            the_characters = Character.get_character_list()
            the_characters.append(new_goblin_character)
            the_characters.append(new_gladiator_character)
            print(the_characters)
        """
        if Character.__character_list == None:
            Character.__character_list = []
        return Character.__character_list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again don't get bogged down in the details. This has just been included as an example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Playing The Game&lt;/strong&gt;&lt;br&gt;
Now of course this is the important part. Actually playing the game. There are detailed instructions in the &lt;a href="https://github.com/fergus-mk/goblins_and_gladiators_game/tree/main"&gt;repo&lt;/a&gt;, but I wanted to give you a quick preview. Basically creating characters looks a little like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flame_goblin = characters.Goblin('flame goblin', 'fire')
fighter = characters.Gladiator('fighter')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then get them to attack each other (or use healing spells and other special abilities):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flame_goblin.attack(fighter)
flame goblin attacked fighter who now has 8 hp"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fight continues until one character dies and loses. The game also shows some of the graphics I showed earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This &lt;a href="https://www.linkedin.com/learning/programming-foundations-object-oriented-design-3"&gt;course&lt;/a&gt; by Olivia Chiu Stone and Baron Stone is great for learning about object oriented design (note it is paid for)&lt;/li&gt;
&lt;li&gt;This &lt;a href="https://www.youtube.com/watch?v=2AK7j8pIh-0&amp;amp;t=2709s"&gt;video&lt;/a&gt; is a great example of a simple Pokemon text based game&lt;/li&gt;
&lt;li&gt;This &lt;a href="https://copyassignment.com/python-oop-projects-source-code-and-example/"&gt;page&lt;/a&gt; has some more example project designs &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>gamedev</category>
      <category>oop</category>
    </item>
  </channel>
</rss>
