Git, Example of Application

Git
Datalab
VSCode
Python project
Lab 1
Author

Ludovic Deneuville

  • pyproject.toml -> remplace requirements.txt & co
  • typst

Objectives

The objectives of this first tutorial are as follows:

  • Overview of the structure of a backend/frontend application
  • Getting to grips with VS Code and its settings
  • Reminders on using Git
  • Init your projet tools

This tutorial combines explanations and code phases.

The explanations in this tutorial should not take precedence over those of your instructor. Use them as a knowledge base for later, but always prefer oral explanations.

You will be using the following tools:

  • Python 3.13
  • Visual Studio Code
  • Git
  • PostgreSQL
  • cloudBeaver
Caution

Don’t skip a step that didn’t work, telling yourself that it doesn’t matter.

This may cause problems later.

1 Accounts and Configuration

The practical labs will be carried out on Datalab SSPCloud: https://datalab.sspcloud.fr/

Caution

You can also work on the GENES Datalab, but you’ll have to perform certain steps manually.

https://onyxia.lab.groupe-genes.fr/

1.1 GitHub account

Note

GitHub is a web-based platform that provides hosting for software development and version control using Git.

It’s widely used by developers to collaborate on projects.

    • or sign up if you don’t already have one

1.2 GitHub Token

To avoid having to identify yourself every time you want to push code onto GitHub from a Datalab service, you will to generate a Token.

Caution

If you’re sure your token is still active, you can skip this step. If not, create a new one.

Follow instructions on ENSAI-tools to:

1.3 AI agent

WarningREAD IT carefully

AI is a force multiplier, not a substitute for expertise. If you know your subject, it will elevate your work; if you don’t, it will simply help you make mistakes faster.

Using AI without a solid foundation is like driving a high-speed car without knowing how to steer: you’ll get somewhere quickly, but you might crash along the way.

Using an AI agent directly within VSCode transforms your editor from a simple text tool into an intelligent collaborator.

By having full access to your local files and project structure, the agent understands the specific context of your codebase. This allows it to suggest highly relevant code snippets, automate repetitive boilerplate, and perform complex refactoring tasks without you ever having to leave your development environment.

To use it in VS Code, there are a few steps you need to take first:

2 Repositories creation

Note

For this first tutorial, you will work with your project team on a single remote repository.

One member of the team will create a repository on GitHub and then all the members (including the creator of the GitHub repository) will create their local repositories by cloning this remote repository.

2.1 Remote repository

Warning

A single team member creates this remote repository.

This is the shared central repository for all project members to synchronize their work during labs.

    • On the repository page > ⚙️ Settings > Collaborators > Add people

2.2 Datalab service

Before creating your local repositories, you will launch a VSCode-python service.

But you will not launch directly the catalog service. You will custom it first by:

  • adding/removing some extensions
  • installing needed packages
  • opening ports to the internet

Let’s do this manually:

Note

This script:

  • install packages
  • install/uninstall VSCode extensions

More about initialization script

Important

If you don’t expose both ports, you will have no choice but to start over with creating your VScode-python service and everything that follows.

When you change the default settings for starting a service, you can:

  • save that configuration
  • also generate a link that starts the service using that configuration

Example of link: https://datalab.sspcloud.fr/launcher/ide/vscode-python?name=vscode-python&version=2.5.6&s3=default&init.personalInit=«https%3A%2F%2Fraw.githubusercontent.com%2Fludo2ne%2FENSAI-2A-projet-info-template%2Frefs%2Fheads%2Fmain%2Fonyxia_setup.sh»&git.repository=«https%3A%2F%2Fgithub.com%2Fludo2ne%2FENSAI-2A-projet-info-template.git»&networking.user.enabled=true&networking.user.ports[1]=8000

2.3 Local repositories

Once the VSCode service is up and running, your local clone should already be created. 🪄

Let’s check it using a terminal:

    • Top left, icon with 3 horizontal bars > Terminal > New
    • or use shortcut CTRL + SHIFT + C
    • You should see your cloned repository
CautionIf the clone creation failed
    • Manually: File > Open Folder > /home/onyxia/work/<repo_name> > OK
    • Or command: code-server /home/onyxia/work/ENSAI-2A-projet-info-template

This opens a new tab with your project set as the root of your file explorer.

    • Close the previous tab
    • git remote -v
Important

You should be connected via push and fetch (pull) to the URL of your remote repository, including the token:

$ git remote -v
origin  https://ghp_dadadirladada@github.com/ludo2ne/ENSAI-2A-projet-info-template.git (fetch)
origin  https://ghp_dadadirladada@github.com/ludo2ne/ENSAI-2A-projet-info-template.git (push)

Otherwise, check the same link as above (“If the clone creation failed”) to connect your repository properly.

3 Repository content

Folder Description
backend/ The heart of your application, following a Layered Architecture
frontend/ The user interface code (Streamlit application).
doc/ Stores project documentation, diagrams, tracking and report
data/ Used for storing persistent data, such as database files or datasets.
.github/ Contains CI/CD workflows (GitHub Actions) and automation scripts.
.vscode/ Stores editor settings, extensions, and debugger configurations.

In both backend and frontend folders, you will find these files :

File Description
pyproject.toml Defines project metadata, dependencies, and build configurations.
uv.lock A lockfile that ensures exact, reproducible dependency versions.
logging.yaml Configuration file defining how the application logs information.

Let’s focus on some files.

3.1 README

The README file is essential for every project. It contains all the information needed to describe, install and use the application.

Follow instructions to :

Tip

You will notice that you need to connect to a PostgreSQL database.

    • Ressources tab > Persistent volume size: 1Gi

3.2 VSCode settings

Note

The .vscode/settings.json file is the central configuration file for VS Code, allowing you to customize the editor through code instead of menus.

You use it to control everything from themes and fonts to code formatting, auto-completion behaviors, and extension settings.

Most of these settings concern the automatic formatting of code when you save a file:

  • Formatter: Ruff
  • "editor.formatOnSave": true: apply format when you save a file
  • "editor.insertSpaces": true: replace tabulation by spaces

3.3 pyproject.toml

A pyproject.toml file centralizes project configuration. Here is what it contains:

  • Project Metadata: Name, version, description, authors, etc.
  • Dependencies: Core libraries required to run the app
    • including dev libraries (only for development)
  • Build System: Instructions for Python tools on how to install and build your package.
  • Tool Configuration: Settings for various tools (e.g., pytest, ruff, etc.) to avoid having multiple config files.

3.4 uv.lock

Note

uv is the engine that manages your project, and uv.lock is the snapshot that guarantees everyone uses the exact same setup.

uv is an extremely fast Python package and project manager, written in Rust. It is designed to replace multiple tools at once (like pip and venv).

  • It is significantly faster than pip for installing dependencies
  • It manages Python versions, virtual environments, and package dependencies

The uv.lock file is a “lockfile” that records the exact state of your project’s dependency tree.

  • Deterministic Installs: While pyproject.toml might say “I need FastAPI version 0.100 or higher,” the uv.lock file records that you are using exactly FastAPI 0.109.2 and specifies the exact versions of every sub-dependency
  • Reproducibility: It ensures that if a teammate clones your repo or if you deploy to a server, they get the identical environment you have. It eliminates the “it works on my machine” problem
  • Integrity: It contains hashes for every package, ensuring that the files downloaded are exactly what was expected and haven’t been tamelred with

4 Application example

You might design a Web services (mandatory) and/or a Menu-driven interface (optional):

  • Web services: User interaction via API endpoints to retrieve data
  • Menu-driven apps: User interaction via navigation menus

4.1 Web services vs Menu-driven

To understand the difference, let’s look at how you access data from the same source (Star Wars API):

4.1.1 The API (Webservice)

Target: Machines/Software 🤖

  • URL: https://swapi.info/api/people/35
  • Experience: You receive a raw, structured data format (usually JSON). There is no design, no colors, just the “pure” information.
  • Goal: Efficiency and integration (so another program can read the data easily).

4.1.2 The Web Interface (Menu-driven)

Target: Humans 👤

  • URL: https://swapi.info/people/padme-amidala
  • Experience: You click on links, navigate through menus, and see a beautifully formatted webpage with images, colors, and buttons.
  • Goal: Ease of use and visual presentation.

4.2 A webservice

We will discuss webservices in more detail in Lab 3.

    • Once it starts, don’t click on the pop-up. It won’t work!
TipHow to query it
  • Internal: Use curl within the service environment.
  • External: Use the public URL to access the service through the exposed port (5000).

Let’s start by querying the web service from the inside:

Then from the outside:

Note

Using this link, even your neighbor can access it.

You are being redirected to the /docs endpoint, the Swagger API.

If the request was successful, you will receive an HTTP 200 code and a response body.

Code Range Type Category Brief Description
2xx Success Success The action was successfully received, understood, and accepted.
4xx Client Error Client Error The request contains bad syntax or cannot be fulfilled by the client.
5xx Server Error Server Error The server failed to fulfill an apparently valid request.
Code Type Description
200 Success OK: The request succeeded.
201 Success Created: Request fulfilled and a new resource was created.
400 Client Error Bad Request: The server cannot process the request due to client error.
401 Client Error Unauthorized: Authentication is required and has failed or not been provided.
403 Client Error Forbidden: The client does not have access rights to the content.
404 Client Error Not Found: The server cannot find the requested resource.
405 Client Error Method Not Allowed: The request method (GET, POST, etc.) is not supported.
500 Server Error Internal Server Error: A generic error message when an unexpected condition was encountered.
502 Server Error Bad Gateway: The server received an invalid response from an upstream server.
503 Server Error Service Unavailable: The server is not ready to handle the request (e.g., maintenance).

🚧

TODO Pas la bonne manière de faire, il faut utiliser un PlayerReadModel sans pwd et token

Feel free to test GET requests using curl and/or the Swagger

Caution

For other types of http request (PUT, POST, DELETE), you will see how to make these requests in a later tutorial.

This diagram shows how a request to fetch a player travels through the application layers, from the API router to the database.

sequenceDiagram
    participant Client as Client
    participant Router as API Router (main)
    participant WS as PlayerController
    participant Service as PlayerService
    participant DAO as PlayerDao

    Client->>Router: GET /player/1
    Note right of Router: Route matching /player
    Router->>WS: player_by_id(id_player=1)
    
    WS->>Service: find_by_id(1)
        
    Service->>DAO: find_by_id(1)
    DAO-->>DAO: Database request <br/>SELECT *<br/>FROM player<br/> WHERE id = 1
    DAO-->>Service: Player instance (or None)
    Service-->>WS: Player instance (or None)

    alt Player found
        WS-->>Client: 200 OK <br/> JSON {id_player: 1, username: "...", ...}
    else Player not found
        WS-->>Client: 404 Not Found <br/> {"detail": "Player not found"}
    end

Now that our API is up and running, it’s quite satisfying to see it working. However, interacting with raw JSON isn’t exactly a luxury—this is where a proper user interface comes in.

5 Git

Note

You’re going to do a few basic things with Git :

  • Add files to the repository
  • Create save points
  • Send your local modifications to remote repositories
  • Update your local repository

5.1 Git routine

You modified some files, it’s time to update the remote repository:

if "you're the first teammate to push the code":
  everything_is_fine = True
else:
  action = "you have to pull first"
  conflict_probability = 0.95

The sequence of Git commands should become automatic.

Read the Git messages carefully!

If you need to simulate a conflict, ask a teammate to edit the first line of the README, then add, commit, and push.

On your end, do the same thing; it will prompt you to pull, and that’s it.

5.2 Handling conflicts

If a teammate has already pushed changes to the same file you are working on, Git will block your push and ask you to pull first. During this process, you might encounter a Merge Conflict.

Don’t panic! A conflict just means Git doesn’t know which version of the code to keep. Follow these steps:

<<<<<<< HEAD
Your local changes (the ones you just wrote)
=======
The remote changes (the ones your teammate pushed)
>>>>>>> [commit_hash_or_branch_name]
    • Keep only your code: Accept Current Change
    • Keep only the teammate’s code: Accept incoming change
    • Combine both: manually edit the code, then delete all markers

Having a conflict isn’t a big deal!

Having a conflict isn’t a big deal!

Having a conflict isn’t a big deal!

Conflict ≠ Error

This simply happens when Git encounters 2 versions and it doesn’t have a 🔮 or a 🎲 to choose which is the right one.

To avoid conflicts, get organised with your team to avoid working on the same files at the same time as much as possible.

Now that you’ve seen what an application looks like and you’re up and running with Git, let’s create your real project repository.

6 Create your project repository

Tip

You can start from scratch, or use a template.

A team member :

    • Repository name: ensai-it-project-2a-team<N>.
    • Public (recommended) or Private
    • Check Add a README file
    • .gitignore : Python
    • Choose a license : Apache, GNU, MIT…
ImportantMandatory

Next, each team member :

    • In the same VSCode service (⚠️ use your token) or in a new one
    • doc/tracking/2025.09.03-week1.md: the first weekly point
    • README.md
    • main.py
Caution

Afterwards, you’ll make sure that your depot is “tidy”, in the same way as described in the previous section.

6.1 .env file

This file will contain environment variables that will be used, for example, to connect to the PostgreSQL database.

6.2 PostgreSQL database

You can either:

  • Each set up your own PostgreSQL service and connect your application to it
  • Set up and share a single database and have everyone connect to it
Approach Pros Cons
Shared DB Zero setup: Everyone connects to the same URL.
Data Sync: Everyone sees the same rows.
High Risk: One accidental DROP TABLE or DELETE breaks the project for everyone.
Conflict: You can’t test “deleting a user” if your teammate is currently using that user.
Isolated DB Safety: You can break your local table without consequences.
Independence: You can test different data states simultaneously.
Sync Effort: You must remember to git commit the .sql file every time you change a column.
Drift: If someone forgets to commit, the team’s environments will diverge.
Caution

In any case, be sure to version one or more SQL files so that you can rebuild your database and data from scratch.

The aim of this tutorial was to get you up to speed on using Git, and to help you discover and understand how a layered application works.

End of the Lab

Important

When you have finished coding, don’t forget to:

    • If your service is terminated, all unpushed code is lost…
    • to free up reserved resources