Supprimer Rendre public Rendre privé Add tags Delete tags
  Ajouter un tag   Annuler
  Supprimer le tag   Annuler
  • • DevOps notes •
  •  
  • AI
  • Tags
  • Connexion

K9s - Manage Your Kubernetes Clusters In Stylehttps://k9scli.io/

  • kubernetes
  • kubernetes

Kubernetes CLI To Manage Your Clusters In Style!

6 hours ago Permalien
cluster icon
  • Building Kubernetes Operators : A comprehensive, hands-on and free course for building production-ready Kubernetes operators using Kubebuilder.
  • Argo CD - Declarative GitOps CD for Kubernetes : Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
  • Kubernetes Spec : Reference Guide and Documentation : Find the documentation for all Kubernetes resources, properties, types, and examples.

Building Kubernetes Operatorshttps://piyushjajoo.github.io/k8s-operators-course/

  • kubernetes
  • kubernetes

A comprehensive, hands-on and free course for building production-ready Kubernetes operators using Kubebuilder.

6 hours ago Permalien
cluster icon
  • Kubernetes Spec : Reference Guide and Documentation : Find the documentation for all Kubernetes resources, properties, types, and examples.
  • Argo CD - Declarative GitOps CD for Kubernetes : Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
  • K9s - Manage Your Kubernetes Clusters In Style : Kubernetes CLI To Manage Your Clusters In Style!

Argo CD - Declarative GitOps CD for Kuberneteshttps://argo-cd.readthedocs.io/en/stable/

  • kubernetes
  • kubernetes

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.

6 hours ago Permalien
cluster icon
  • K9s - Manage Your Kubernetes Clusters In Style : Kubernetes CLI To Manage Your Clusters In Style!
  • Building Kubernetes Operators : A comprehensive, hands-on and free course for building production-ready Kubernetes operators using Kubebuilder.
  • Kubernetes Spec : Reference Guide and Documentation : Find the documentation for all Kubernetes resources, properties, types, and examples.

Kubernetes Spec : Reference Guide and Documentationhttps://kubespec.dev/

  • kubernetes
  • kubernetes

Find the documentation for all Kubernetes resources, properties, types, and examples.

6 hours ago Permalien
cluster icon
  • Building Kubernetes Operators : A comprehensive, hands-on and free course for building production-ready Kubernetes operators using Kubebuilder.
  • K9s - Manage Your Kubernetes Clusters In Style : Kubernetes CLI To Manage Your Clusters In Style!
  • Argo CD - Declarative GitOps CD for Kubernetes : Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.

AWS (SAA-C03) Mind maphttps://www.mindmeister.com/app/map/3471885158?t=lE6MXlXHYC

  • aws
  • aws

6 hours ago Permalien
cluster icon
  • Floci: AWS Local Emulator alternative · GitHub : Light, fluffy, and always free - The AWS Local Emulator alternative

Is It Worth Automating?https://agileadam.com/worth-automating/

  • tools
  • tools

Is It Worth Automating?

Sometimes it costs you more time to automate something than it does to just do it.

6 hours ago Permalien
cluster icon
  • IP Subnet Calculator :
  • Chmod Calculator :

IP Subnet Calculatorhttps://www.calculator.net/ip-subnet-calculator.html

  • linux
  • tools
  • linux
  • tools

6 hours ago Permalien
cluster icon
  • Chmod Calculator :
  • Process monitoring : ps Command ps → Current shell process status ps -e → All running processes ps aux → All in BSD style with details ps -ef → Running process with detai...
  • Computer Storage / Disk Partition : Computer Storage Local → RAM / HDD / SSD DAS (Direct Attached Storage) USB HDD / DVD SAN (Storage Area Network) through iSCSI cable or fiber ...
  • Journalctl : journalctl journalctl -u sshd show only log for sshd logger hello write in syslog journalctl -f log is live nano /etc/systemd/journald.c...
  • Linux Boot Process / Optimizing Boot Performance : Linux Boot Process → Older Version BIOS → Basic Input / Output System executes MBR MBR → Master Boot Record executes GRUB GRUB → Grand U...

Chmod Calculatorhttps://nettools.club/chmod_calc

  • linux
  • tools
  • linux
  • tools

6 hours ago Permalien
cluster icon
  • IP Subnet Calculator :
  • Navigating File System / Linux filetypes : ls -l → List pwd → Print working directory dr-xr-xr-x | directories -rw-r--r-- | file Linux File Types Symbol Type - Regular file d Dire...
  • Vi Editor : Vi Editor Commands i → insert mode ESC → escape to command mode r → replace mode x → delete character dd → delete line yy → copy line p → paste v → v...
  • Package Management : System Updates & Software Install dnf (yum) → RedHat → /etc/yum.repos.d apt-get → Debian rpm → RedHat package management standalone package to ...
  • Journalctl : journalctl journalctl -u sshd show only log for sshd logger hello write in syslog journalctl -f log is live nano /etc/systemd/journald.c...

SadServers: Linux, DevOps & SRE Labs | Interview & Hiring Assessmenthttps://sadservers.com/

  • linux
  • adminsys
  • linux
  • adminsys

Hands-On Linux & DevOps
Real Challenges. Real Infra. Real Skills.

Master Linux & DevOps troubleshooting on live servers.

Fun, real-world challenges for engineers
and powerful assessments for hiring teams.

6 hours ago Permalien
cluster icon
  • Linux Boot Process / Optimizing Boot Performance : Linux Boot Process → Older Version BIOS → Basic Input / Output System executes MBR MBR → Master Boot Record executes GRUB GRUB → Grand U...
  • Navigating File System / Linux filetypes : ls -l → List pwd → Print working directory dr-xr-xr-x | directories -rw-r--r-- | file Linux File Types Symbol Type - Regular file d Dire...
  • Computer Storage / Disk Partition : Computer Storage Local → RAM / HDD / SSD DAS (Direct Attached Storage) USB HDD / DVD SAN (Storage Area Network) through iSCSI cable or fiber ...
  • Apache and Nginx : Apache Web Server dnf install httpd nano /etc/httpd/conf/httpd.conf nano /var/www/html/index.html systemctl restart httpd systemctl stop firewalld N...
  • Package Management : System Updates & Software Install dnf (yum) → RedHat → /etc/yum.repos.d apt-get → Debian rpm → RedHat package management standalone package to ...

Enroll - Reverse-engineering servers into Ansiblehttps://enroll.sh/

  • ansible
  • adminsys
  • ansible
  • adminsys

Get an existing Linux host into Ansible in seconds.

Enroll inspects a Debian-like or RedHat-like system, harvests the state that matters, and generates Ansible roles/playbooks so you can bring snowflakes under management fast.

6 hours ago Permalien
cluster icon
  • Ansible : Control node → server which runs Ansible Modules → command executed on client side (found pre-made modules on Ansible website) Task → multiple proced...
  • SadServers: Linux, DevOps & SRE Labs | Interview & Hiring Assessment : Hands-On Linux & DevOps Real Challenges. Real Infra. Real Skills. Master Linux & DevOps troubleshooting on live servers. Fun, real-world challenges fo...

Floci: AWS Local Emulator alternative · GitHubhttps://github.com/floci-io/floci

  • aws
  • aws

Light, fluffy, and always free - The AWS Local Emulator alternative

6 hours ago Permalien
cluster icon
  • AWS (SAA-C03) Mind map :

Adding Tests to a Multi-File Project/shaare/PAwfIg

  • python
  • python

Adding Tests to a Multi-File Project

Standard Project Layout with Tests

To maintain a clean and organized codebase, it is standard practice to separate your application code from your test code. This is typically achieved by creating a dedicated tests directory at the project's root level.

  • The project root contains the main application package (e.g., devops_utils) and the tests directory as siblings.
  • The tests directory houses all the test files. It is common for the structure inside tests to mirror the structure of the application package to keep tests organized as the project grows.
  • It is also good practice to place an empty __init__.py file inside the tests directory to ensure it can be treated as a package if needed, although pytest's discovery mechanism is powerful enough to work without it in most cases.

Importing Application Code into Tests

To test your application code, your test files must import the functions, classes, and variables that need to be verified. The standard and most robust way to do this is by using absolute imports that start from the project root.

  • A test file, such as tests/test_file_ops.py, will use an import statement like from devops_utils.file_ops import check_file_extension.
  • This import syntax assumes that the project's root directory is on Python's module search path (sys.path).
  • Attempting to run a test file directly as a Python script will fail with a ModuleNotFoundError, because the project root is not automatically added to the path in that context. This is why a test runner like pytest is necessary.

Running pytest for Project Discovery

The pytest framework is designed to handle the complexities of testing structured projects. When you run pytest from your project's root directory, it intelligently prepares the environment for test execution.

  • Pytest begins by scanning upwards from the current directory to find a configuration file (like pyproject.toml or pytest.ini), which it uses to identify the project's root.
  • Once the root is identified, pytest automatically adds this directory to sys.path.
  • With the path correctly configured, the absolute imports within your test files will resolve successfully, allowing your tests to find and execute the application code.

Robust Test Execution with python -m pytest

While running pytest directly is often sufficient, an even more reliable method is to invoke it as a module using the python -m flag. This approach is highly recommended, especially in automated environments like CI/CD pipelines.

  • The command python -m pytest guarantees that the current working directory is added to sys.path before pytest begins its execution.
  • This method eliminates many path-related ambiguities that can arise in complex project structures or different operating environments.
  • It is considered the most robust and explicit way to run your test suite, ensuring consistent behavior across different machines and setups.

Common Pitfalls & How to Avoid Them

When setting up tests for a multi-file project, there are several common issues that can be easily avoided.

  • ModuleNotFoundError during test runs: This is the most frequent problem and is almost always caused by running pytest from the wrong directory. To avoid this, always run pytest from the project root, or preferably use python -m pytest. An editable install (pip install -e .) provides the most robust solution.
  • Tests importing other tests: This is considered an anti-pattern as it creates implicit dependencies between tests. If you need to share test logic or data, use conftest.py to define shared fixtures.
  • Using relative imports in tests: Imports like from ..devops_utils import ... are fragile and should be avoided in test files. Always use absolute imports from the project root (e.g., from devops_utils.file_utils import ...).
1 month ago Permalien
cluster icon
  • Lambda Functions : Lambda Functions Python functions defined with def allow multiple statements, clear naming, and support for docstrings, making them ideal for complex...
  • Working with CSV files : Working with CSV files CSV (Comma Separated Values) is a plain-text tabular format where each line is a row and fields are delimited (commonly by com...
  • Python package and subpackage : Introduction to Packages (__init__.py) What is a Package? A Python package provides a way to structure a project's module namespace by using directori...
  • Python Functions Are First‑Class Citizens : Python Functions Are First‑Class Citizens In Python, functions behave like any other object (strings, ints, lists). Because they are "first‑clas...
  • Log Levels in Practice : Log Levels in Practice Python defines five standard levels with increasing severity: DEBUG (10): Detailed diagnostic information. INFO (20): Confirm...

Editable Installs with pyproject.toml/shaare/oYfOwA

  • python
  • python

Editable Installs with pyproject.toml

The Python interpreter doesn't automatically know about our project's structure. The modern and most robust solution is to formally define our project as an installable package. By creating a standard pyproject.toml metadata file, we can perform an "editable install" using the command pip install -e .. This seamlessly links our source code into the virtual environment, making our packages importable from anywhere without manual path hacks or special commands. This is the standard, professional workflow for developing Python applications.

The pyproject.toml File

The pyproject.toml file is the modern, unified standard for configuring Python projects, replacing older files like setup.py.

  • It is written in the simple and readable TOML (Tom's Obvious, Minimal Language) format.
  • It defines the project's build system, such as setuptools, in the [build-system] table.
  • It specifies essential project metadata, like the package name, version, and dependencies, in the [project] table.
  • It can also serve as a central location for configuring development tools like formatters and linters.

Editable Installs: pip install -e .

An "editable" or "development" install is a special mode for installing packages with pip.

  • The command pip install -e . installs the project from the current directory in "editable" mode.
  • Instead of copying files, it creates a special link from the virtual environment's site-packages directory back to the original source code.
  • The main benefit is that any changes made to the source .py files are immediately reflected in the installed package without needing to run pip install again.

Solving the Import Problem Permanently

Performing an editable install provides a definitive solution to the path and import issues encountered during development.

  • After an editable install, the project is effectively on sys.path for the entire activated virtual environment.
  • There is no longer any need to manually set the PYTHONPATH environment variable.
  • You can now run scripts that are inside packages directly, and they will be able to use absolute imports from the project root.
  • This approach creates a self-contained and reproducible environment, which is the standard for professional Python development.

Console Scripts vs. python -m

While a script with an if __name__ == "__main__" block can be run with python -m, defining a console script in pyproject.toml is the preferred professional approach.

  • User Experience: A console script (ping-check) is short and intuitive. A python -m command is long, exposes the internal module path, and is easy to mistype.
  • Abstraction: A console script hides your project's internal structure. You can refactor your code internally, and as long as you update the pyproject.toml file, the command remains the same for the user. The python -m command breaks if you rename or move the target file.
  • Clarity of Intent: Declaring a script in pyproject.toml clearly marks it as a public, supported command-line interface for your package.
[project]
name = "devops_utils"
version = "0.1.0"

[project.scripts]
check_host = "devops_utils.network_utils.check_host:main"
1 month ago Permalien
cluster icon
  • Variables, comments : Variables: Naming Values Naming Guidelines: Must start with a letter or underscore (_) and can contain letters, numbers, and underscores. Use snake_...
  • Making HTTP Requests : Making HTTP Requests The requests library simplifies HTTP interactions by abstracting raw HTTP details, making it ideal for DevOps automation tasks. ...
  • Temporary Files and Directories : Temporary Files and Directories Automation scripts often need scratch space for intermediate data without cluttering the filesystem or risking name c...
  • Enhancing Functions: Decorators : Enhancing Functions: Decorators A decorator is a callable that takes another function, adds behaviour before and/or after it runs, and returns a new ...
  • Custom Exceptions: Tailoring Error Signals : Custom Exceptions: Tailoring Error Signals Built-in exceptions are great, but often too generic for application-specific failures. A custom excepti...

Running Python modules/shaare/k00RHQ

  • python
  • python

Running Scripts: python -m vs. python file.py

The Core Difference: What is "Entry Point Zero"?

The key to understanding the difference lies in the first entry of sys.path. When Python initializes, it needs to know where to start looking for modules. The way you call it determines this "entry point zero".

  • When you run a script directly using python path/to/script.py, the interpreter's main task is to execute that specific file. It sets the first entry of sys.path to be the directory that contains the script.

  • When you run a script as a module using python -m package.module, the interpreter's goal is to locate and run a module within an importable package. It sets the first entry of sys.path to be the current working directory from which the command was executed. This allows absolute imports from the project root to succeed.

Best Practice: Separating Library Code from Scripts

While you can run any file with python -m, it can lead to a RuntimeWarning if the file is both a library (meant to be imported) and a script (meant to be run). The best practice is to separate these roles.

  • Library Modules: These files (like our file_ops.py and network_ops.py) should contain only reusable functions and classes. They should not contain an if __name__ == "__main__": block for complex script logic.
  • Runner Scripts: For any action you want to make runnable from the command line, create a new, separate script.

Common Pitfalls & How to Avoid Them

  • Running scripts inside packages directly with python file.py will often cause ModuleNotFoundError for absolute imports. Avoid this by always running packaged scripts from the project root using python -m.
  • Making a single file both a complex library and a runnable script can lead to RuntimeWarning. Avoid this by separating concerns: create dedicated runner scripts that import from your library modules.
  • Forgetting the module path when using -m. The command must be the full dotted path to the script from the project root (e.g., python -m package.subpackage.script).
1 month ago Permalien
cluster icon
  • If / Elif / Else Logic : If / Elif / Else Logic Control the flow of scripts based on conditions using if, elif, and else. The if Statement An if statement executes a block of ...
  • Python Functions Are First‑Class Citizens : Python Functions Are First‑Class Citizens In Python, functions behave like any other object (strings, ints, lists). Because they are "first‑clas...
  • The Iteration Protocol : The Iteration Protocol We use for item in sequence: all the time. But how does Python get each item? Iterable: An object that can be looped over. It...
  • Exceptions : Common Built‑in Exceptions Python ships with a rich hierarchy of exception classes; most automation errors fall into a small, predictable subset. A...
  • Handling Errors and Status Codes : Handling Errors and Status Codes HTTP status codes communicate the outcome of an API request, and handling them correctly is key to robust automation...

Python package and subpackage/shaare/9j4UUQ

  • python
  • python

Introduction to Packages (__init__.py)

What is a Package?

A Python package provides a way to structure a project's module namespace by using directories. It enables a hierarchical organization of modules, mirroring the file system's structure.

  • Any directory that contains a file named __init__.py is recognized by the Python interpreter as a package.
  • A package directory can contain not only module files (ending in .py) but also other subdirectories that are themselves packages.

The Role of __init__.py

  • Its primary role is to serve as a marker, signaling to Python that the directory it resides in should be treated as a package. In older versions of Python, a directory without this file would not be recognized as a package. While newer versions have more lenient rules, explicitly including __init__.py is the standard and most compatible method.
  • The second purpose is for package initialization. Any code written inside the __init__.py file is executed once when the package or any of its modules are first imported, which can be useful for setting up package-level resources. For many packages, this file can simply be left empty.

Importing from a Package

  • You can import the entire module using the full path, such as import devops_utils.file_ops. Accessing its contents would then require the full prefix, like devops_utils.file_ops.check_file_extension().
  • Alternatively, you can use the from keyword to import the module more directly, as in from devops_utils import file_ops, which then allows access via file_ops.check_file_extension().
  • For even more direct access, you can import specific functions or variables, for example, from devops_utils.file_ops import check_file_extension. This makes the function available to be called directly as check_file_extension().

Using __init__.py to Control Imports

  • By importing members from the package's modules into the __init__.py file itself, you can make them appear as if they belong to the top-level package namespace.
  • This technique can create a simpler, more user-friendly API for your package, but it can also obscure the underlying module structure.

Importing from Subpackages

Project Structure with Subpackages

To improve organization, we can group related modules into their own dedicated subpackages. A subpackage is a directory inside a parent package that contains its own __init__.py file.

  • A top-level package, like devops_utils, can contain multiple subpackages.
  • For example, we can create a file_utils subpackage for file-related modules and a network_utils subpackage for networking modules.
  • Each of these subdirectories must contain an __init__.py file (which can be empty) to be recognized by Python as a package.

Absolute Imports

An absolute import provides the complete, explicit path to a module starting from a top-level directory that is on Python's search path (sys.path).

  • The syntax follows the project's directory structure, such as from package.subpackage.module import function.
  • This is the most recommended and readable way to import modules, particularly in top-level scripts that execute the application's logic.
  • Absolute imports are unambiguous and clearly state the origin of the imported code, which greatly improves code maintainability. For example, a script outside the devops_utils package would use from devops_utils.file_utils.file_ops import check_file_extension to access a function.

Relative Imports

A relative import specifies the path to a module based on the location of the file performing the import. This is done using dot notation.

  • The syntax uses dots to navigate the package hierarchy: . refers to the current package, while .. refers to the parent package.
  • An import like from .sibling_module import name brings in a name from a module in the same directory. An import like from ..parent_sibling.module import name navigates one level up and then down into a sibling package.
  • Relative imports are primarily used for communication within a package. Their main advantage is that they make the package self-contained; if you rename the top-level package, the internal relative imports will not break.

The ImportError Trap with Relative Imports

A significant pitfall arises when you attempt to directly execute a Python file that contains relative imports. This action will almost always result in an error.

  • Running a script like python devops_utils/network_utils/network_ops.py will raise an ImportError: attempted relative import with no known parent package.
  • This happens because when a file is run directly, Python sets its name (__name__) to "__main__" and does not recognize it as being part of a package. Consequently, it cannot resolve relative paths like . or ...
  • The rule of thumb is that relative imports should only be used for intra-package imports, and the application should be started from a top-level script that uses absolute imports to access the package's functionality.
1 month ago Permalien
cluster icon
  • Mocking : Mocking Fundamentals Introduction When unit testing DevOps scripts that interact with external systems, tests can become slow, unreliable, difficult ...
  • Exceptions : Common Built‑in Exceptions Python ships with a rich hierarchy of exception classes; most automation errors fall into a small, predictable subset. A...
  • Classes and Objects : Classes and Objects Beyond Built-ins: Python lets you define your own data types using class. Class: A blueprint or template for creating objects. De...
  • Functions, Docstrings : Functions Functions package reusable code into named blocks, improving modularity, readability, and testability. They prevent duplication (DRY) and ma...
  • Handling Authentication : Handling Authentication APIs often require authentication to control access, rate limits, and auditing. Without authentication, requests to protected...

Python Modules and the import System/shaare/XckVlw

  • python
  • python

Python Modules and the import System

What is a Module?

  • A module in Python corresponds directly to a single file containing Python code.
  • The module's name is derived from its filename.
  • Any file with a .py extension can be treated as a module.
  • The name used to import the module is the filename without the .py suffix. For example, a file named file_ops.py is imported as the file_ops module.

The import Statement

  • The most straightforward way to import a module is with import module_name
  • To use functions, variables, or classes from the imported module, you must prefix them with the module name and a dot, such as module_name.function_name.
  • This method creates a dedicated namespace for the imported module, which is highly effective at preventing name collisions. For instance, a variable named CONFIG in your script will not conflict with module_name.CONFIG.
  • It enhances code clarity by making it obvious where each function or variable originates, which is especially helpful in larger projects.

The from...import Statement

  • It's possible to bring only specific objects from a module with from ... import ....
  • You can use the as keyword to rename an imported object, for example, from file_ops import parse_yaml_file as parse_yaml.
  • This approach can make code more concise because it requires less typing (parse_yaml() instead of file_ops.parse_yaml_file()).
  • The primary drawback is the increased risk of name collisions. If you import a function named my_function and later define your own function with the same name, the original import will be overwritten.
  • Using from module import * is strongly discouraged because it imports all public names from the module, which can pollute the local namespace and make the code difficult to read and debug.

How Python Finds Modules: sys.path

When you execute an import statement, Python needs to locate the corresponding module file. It does this by searching through a specific list of directories.

  • The search path is stored in a list of strings called sys.path, which is part of the standard sys module.
  • The sys.path list is automatically populated and typically includes the directory of the script that is currently running, directories specified in the PYTHONPATH environment variable, and the default locations where Python and third-party packages are installed.
  • The fact that the script's own directory is the first entry on this path is why a script like main.py can seamlessly import utils.py when both files are located in the same folder.

Example of main.py

print("Main script starting...")

from devops_utils import (
    check_file_extension,
    is_host_up,
    check_hosts_from_config,
)
import sys

print(sys.path)

filenames = ["config.yaml", "script.sh"]

for filename in filenames:
    print(f"Checking {filename}")
    print(f"Result: {check_file_extension(filename)}")

print(f"\nIs localhost up? {is_host_up("localhost")}")
print(
    f"Is nonexistenthost12345 up? {is_host_up("nonexistenthost12345")}"
)

print(
    f"\nAre all hosts from servers_config.yaml up? {check_hosts_from_config("servers_config.yaml")}"
)

Example of file_ops.py

print("Module file_ops is being imported")

from typing import Any

try:
    import yaml
except (ModuleNotFoundError, ImportError):
    print(
        "Warning: PyYAML not found, parse_yaml_file will not work."
    )
    yaml = None

SUPPORTED_EXTENSIONS: list[str] = [".json", ".yaml", ".txt"]

def check_file_extension(filename: str) -> bool:
    """Checks if a file has a supported extension"""
    print(
        f"  - file_ops.check_file_extension called for {filename}"
    )
    return any(
        filename.endswith(ext) for ext in SUPPORTED_EXTENSIONS
    )

def parse_yaml_file(path_str: str) -> dict[str, Any]:
    """Parses a YAML file and returns its contents."""
    print(f"  - file_ops.parse_yaml_file called for {path_str}")
    if yaml:
        with open(path_str, "r") as file:
            return yaml.safe_load(file)
    else:
        return {}
1 month ago Permalien
cluster icon
  • Working with CSV files : Working with CSV files CSV (Comma Separated Values) is a plain-text tabular format where each line is a row and fields are delimited (commonly by com...
  • Concise Iteration: List Comprehensions : Concise Iteration: List Comprehensions Simple for loops to create lists can be verbose. We can leverage list comprehensions to define the list content...
  • Typing : Introduction Python is a dynamically typed language, meaning you can assign values to variables without declaring their types, and type checking happ...
  • Declarative Logging : Declarative Logging Configuration Declarative configuration separates setup from code, making it easier to maintain and adjust. Python’s logging.conf...
  • Working with YAML files : Working with YAML files YAML (“YAML Ain’t Markup Language”) focuses on human readability. Indentation replaces braces and brackets, comments are allo...

Mocking/shaare/G_SN4g

  • python
  • python

Mocking Fundamentals

Introduction

  • When unit testing DevOps scripts that interact with external systems, tests can become slow, unreliable, difficult to set up, or even destructive.
  • Mocking replaces these real dependencies with controlled, fake objects so that tests run quickly and deterministically.
  • Python’s built-in unittest.mock module provides tools to create and configure these mock objects and to track interactions.

What is Mocking?

  • Mocking involves creating objects that mimic the behavior of real functions or classes in a controlled environment.
  • When your code calls a mocked object, you can specify what it returns, simulate exceptions, or inspect how it was called.
  • This allows you to isolate the logic under test and avoid side effects from actual external calls.

Using unittest.mock.patch

  • The patch function replaces a target object with a mock in a specified scope, either for the duration of a function (decorator) or within a context block (with).
  • As a decorator, patch injects the mock into the test function’s parameters; as a context manager, it yields the mock within the with block.
  • It’s important to patch the object where it is looked up in the module under test, not necessarily where it is originally defined.

MagicMock and Configuring Mock Objects

  • When you patch an object, you typically receive a MagicMock instance that you can configure.
  • Use mock.return_value to define what the mock will return when called.
  • Use mock.side_effect to simulate an exception being raised by the mock when invoked, to pass different values to be returned by each execution, or to pass a calable to replace the implemented function.
  • Assertion methods like assert_called_with and assert_called_once let you verify interactions with the mock.

Common Mocking Scenarios in DevOps

  • Network API Calls: Mock requests.get or requests.post to simulate successful responses, HTTP errors, or timeouts.
  • Filesystem Operations: Mock functions like open() or os.path.exists() to simulate file presence or content.
  • Subprocess Execution: Mock subprocess.run to avoid running real system commands and control return codes.
  • Time-Dependent Code: Patch time.sleep or mock datetime.now() to remove delays and make time-based tests deterministic.
from unittest.mock import patch, Mock
from pytest_mock import MockerFixture
from dummy_functions import check_file_exists, get_user_data

# Section: Using unittest.mock.patch
def test_check_file_exists_manual_patch() -> None:
    filepath = "/path/to/some/file.txt"

    patcher = patch("dummy_functions.os.path.exists")
    mock_exists = patcher.start()

    mock_exists.return_value = True

    try:
        result = check_file_exists(filepath=filepath)
        mock_exists.assert_called_once_with(filepath)
        assert result is True
    finally:
        patcher.stop()

def test_check_file_exists_context_manager() -> None:
    filepath = "/path/to/some/file.txt"

    with patch("dummy_functions.os.path.exists") as mock_exists:
        mock_exists.return_value = True

        result = check_file_exists(filepath=filepath)
        mock_exists.assert_called_once_with(filepath)
        assert result is True

@patch("dummy_functions.os.path.exists")
def test_check_file_exists_decorator(mock_exists: Mock) -> None:
    filepath = "/path/to/some/file.txt"

    mock_exists.return_value = True

    result = check_file_exists(filepath=filepath)
    mock_exists.assert_called_once_with(filepath)
    assert result is True

def test_check_file_pytest_mocker(mocker: MockerFixture) -> None:
    filepath = "/path/to/some/file.txt"

    mock_exists = mocker.patch("dummy_functions.os.path.exists")
    mock_exists.return_value = True

    result = check_file_exists(filepath=filepath)
    mock_exists.assert_called_once_with(filepath)
    assert result is True

# Section: MagicMock and Configuring Mock Objects
def test_get_user_data_success(mocker: MockerFixture) -> None:
    mock_api_response: dict[str, str | int] = {
        "id": 1,
        "name": "test user",
    }

    mock_get = mocker.patch("dummy_functions.requests.get")
    mock_get.return_value.status_code = 200
    mock_get.return_value.json.return_value = mock_api_response

    data = get_user_data(user_id=1)

    mock_get.assert_called_once_with(
        "https://api.example.com/users/1"
    )
    assert data == mock_api_response

Example of dummy_function.py

import requests
import os
import subprocess
from typing import Optional, Any

def get_user_data(user_id: str | int) -> dict[str, str | int]:
    response = requests.get(
        f"https://api.example.com/users/{user_id}"
    )
    print(f"Status code: {response.status_code}")
    response.raise_for_status()
    return response.json()

def check_file_exists(filepath: str | os.PathLike[str]) -> bool:
    return os.path.exists(filepath)

def get_external_ip():
    """Fetches the current external IP from an external service."""
    try:
        response = requests.get(
            "https://api.ipify.org?format=json", timeout=5
        )
        response.raise_for_status()
        return response.json().get("ip")
    except requests.exceptions.RequestException:
        return None

def get_current_user() -> Optional[str]:
    try:
        result = subprocess.run(
            ["whoami"],
            capture_output=True,
            text=True,
            check=True,
            timeout=5,
        )
        return result.stdout.strip()
    except (
        subprocess.CalledProcessError,
        subprocess.TimeoutExpired,
        FileNotFoundError,
    ):
        return None

def fetch_both_endpoints() -> (
    tuple[dict[str, Any], dict[str, Any]]
):
    """
    Fetch data from two endpoints and return their JSON responses as a tuple.
    """
    response2 = requests.get("https://api.example.com/second")
    response2.raise_for_status()
    data2 = response2.json()

    response1 = requests.get("https://api.example.com/first")
    response1.raise_for_status()
    data1 = response1.json()

    return data1, data2

Advanced Mocking Concepts

Using side_effect

  • The side_effect attribute on a mock allows you to control its behavior beyond a single return value.
  • List of values: When side_effect is set to a list, each call to the mock returns the next item in that list, in order.
  • Callable: When side_effect is a function, it is called with the same arguments as the mock, and its return value is used as the mock’s return.
  • Exception: When side_effect is an exception, it will raise that exception when the original function is called.
  • Use a list when you know the sequence and order of calls; use a function when behavior should vary based on arguments.

Choosing between Mock and MagicMock

  • Mock: A simple replacement that only creates attributes when accessed, and raises errors for undefined methods or attributes.
  • MagicMock: Inherits from Mock and implements Python’s magic methods (__len__, __enter__, etc.) by default.
  • Use Mock by default for stubbing external dependencies to catch unintended interactions.
  • Use MagicMock only when mocking objects that require special behavior, such as context managers or iterables.
import subprocess
import pytest
from unittest.mock import MagicMock
from pytest_mock import MockerFixture
from dummy_functions import (
    get_current_user,
    check_file_exists,
    fetch_both_endpoints,
)

# Section: Using side_effect - Exceptions

def test_get_current_user_command_fails(mocker: MockerFixture):
    mock_run = mocker.patch("dummy_functions.subprocess.run")
    mock_run.side_effect = subprocess.CalledProcessError(
        returncode=1, cmd=["whoami"]
    )

    result = get_current_user()

    assert result is None

# Section: Using side_effect - List for Multiple Calls

def test_check_file_exists_side_effect_list(
    mocker: MockerFixture,
):
    mock_exists = mocker.patch(
        "dummy_functions.os.path.exists",
        side_effect=[True, False],
    )

    assert check_file_exists("some/path/one") is True
    assert check_file_exists("some/path/two") is False

    assert mock_exists.call_count == 2

    assert [
        call.args for call in mock_exists.call_args_list
    ] == [("some/path/one",), ("some/path/two",)]

# Section: Using side_effect - Callable for Multiple Calls

def test_fetch_both_endpoints_by_url(mocker: MockerFixture):
    fake_responses: dict[str, MagicMock] = {}

    for url, data in [
        ("https://api.example.com/first", {"first": "data"}),
        ("https://api.example.com/second", {"second": "data"}),
    ]:
        resp = mocker.MagicMock()
        resp.status_code = 200
        resp.json.return_value = data

        fake_responses[url] = resp

    def _fake_get(url: str) -> MagicMock:
        return fake_responses[url]

    mocker.patch(
        "dummy_functions.requests.get", side_effect=_fake_get
    )

    result = fetch_both_endpoints()

    assert result == ({"first": "data"}, {"second": "data"})

# Section: Choosing between Mock and MagicMock

@pytest.mark.xfail(
    reason="Context managers do not work with Mock", strict=True
)
def test_context_manager_with_mock(mocker: MockerFixture):
    fake_cm = mocker.Mock()
    fake_cm.__enter__.return_value = fake_cm
    fake_cm.read.return_value = "file contents"

    mock_open = mocker.patch("builtins.open")
    mock_open.return_value = fake_cm

    with open("somefile.txt") as f:
        contents = f.read()

    mock_open.assert_called_once_with("somefile.txt")
    assert contents == "file contents"

def test_context_manager_with_magicmock(mocker: MockerFixture):
    fake_cm = mocker.MagicMock()
    fake_cm.__enter__.return_value = fake_cm
    fake_cm.read.return_value = "file contents"

    mock_open = mocker.patch("builtins.open")
    mock_open.return_value = fake_cm

    with open("somefile.txt") as f:
        contents = f.read()

    mock_open.assert_called_once_with("somefile.txt")
    assert contents == "file contents"
1 month ago Permalien
cluster icon
  • Working with CSV files : Working with CSV files CSV (Comma Separated Values) is a plain-text tabular format where each line is a row and fields are delimited (commonly by com...
  • Functions: return vs yield : Functions: return vs yield Regular functions execute immediately, run to completion, and return a single value (or None). Generator functions retur...
  • Typing classes : Introduction As our Python automation projects grow, defining custom classes helps model complex objects and should be reflected in type hints for cl...
  • Python Modules and the import System : Python Modules and the import System What is a Module? A module in Python corresponds directly to a single file containing Python code. The module's ...
  • Parametrized Tests : Parametrized Tests Introduction Often, we need to test the same logic with different inputs and outputs, such as validating various IP address or hos...

Parametrized Tests/shaare/0k7HqQ

  • python
  • python

Parametrized Tests

Introduction

  • Often, we need to test the same logic with different inputs and outputs, such as validating various IP address or hostname formats.
  • Writing individual test functions for each case leads to repetitive code and a test suite that is harder to maintain.
  • Parametrized tests allow a single test function to run multiple times with different data, adhering to the DRY principle and simplifying test maintenance.

The Problem: Duplicated Test Logic

  • A function that checks valid hostname character codes must be tested across letters, digits, hyphens, and invalid symbols.
  • Without parametrization, each input case requires its own test function, duplicating the assertion logic.
  • This approach increases verbosity and makes the test suite more error-prone and tedious to update.

Solution: @pytest.mark.parametrize

  • The @pytest.mark.parametrize(argnames, argvalues) decorator takes argument names and a list of value tuples to generate multiple test invocations.
  • Argument names can be provided as a comma-separated string or as a list of strings.
  • Each tuple in the argvalues list corresponds to a separate run of the test function, with tuple elements mapped to argument names.
  • Running Pytest with -v shows each parametrized case as a distinct test, simplifying result interpretation.

The pytest.param Construct

  • The pytest.param() function wraps a set of parameter values and allows you to attach metadata to that invocation:
    • id: a custom label shown in the test report.
    • marks: one or more markers (e.g., pytest.mark.xfail, pytest.mark.skip) applied only to that case.
  • This is useful when you want to:
    • Give human-readable names to complex or ambiguous parameter sets.
    • Mark individual cases as expected failures or skip them selectively.

Customizing Test IDs

  • By default, Pytest creates IDs from parameter values, which may be non-descriptive for complex data.
  • You can use pytest.param(..., id="custom_id") to assign clear, human-readable names to individual cases.
  • Alternatively, an ids list passed to parametrize can specify identifiers in the order of argvalues.
  • Custom IDs make it easier to identify failing cases in test reports and improve overall readability.
import pytest

def is_valid_hostname_char(char: str) -> bool:
    if "a" <= char <= "z":
        return True
    if "0" <= char <= "9":
        return True
    if char == "-":
        return True
    return False

def check_url_status(url: str) -> tuple[int | str, str]:
    if url == "https://google.com":
        return (200, "OK")
    if url == "https://fakesite123.org/notfound":
        return (404, "HTTP_ERROR (404)")
    if url == "http://httpbin.org/status/503":
        return (503, "HTTP_ERROR (503)")
    if url == "http://localhost:1":
        return ("CONNECTION_ERROR", "CONNECTION_ERROR")
    return ("UNKNOWN", "UNKNOWN")

# Section: The Problem: Duplicated Test Logic

"""
a -> True
5 -> True
- -> True
A -> False
_ -> False
"""

def test_is_valid_lower_case_a():
    assert is_valid_hostname_char("a") is True

def test_is_valid_5():
    assert is_valid_hostname_char("5") is True

def test_is_valid_hyphen():
    assert is_valid_hostname_char("-") is True

def test_is_valid_upper_case_A():
    assert is_valid_hostname_char("A") is False

def test_is_valid_underscore():
    assert is_valid_hostname_char("_") is False

# Section: Solution: @pytest.mark.parametrize

@pytest.mark.parametrize(
    "input_char, expected_result",
    [
        ("a", True),
        ("5", True),
        ("-", True),
        ("A", False),
        ("_", False),
        ("!", False),
    ],
)
def test_is_valid_hostname_char(
    input_char: str, expected_result: bool
):
    assert is_valid_hostname_char(input_char) is expected_result

# Section: Customizing Test IDs with pytest.param construct

@pytest.mark.parametrize(
    "input_char, expected_result",
    [
        pytest.param("a", True, id="lowercase_letter_a"),
        pytest.param("z", True, id="lowercase_letter_z"),
        pytest.param("0", True, id="digit_0"),
        pytest.param("-", True, id="hyphen"),
        pytest.param("A", False, id="uppercase_A_invalid"),
        pytest.param("_", False, id="underscore_invalid"),
    ],
)
def test_is_valid_hostname_custom_params(
    input_char: str, expected_result: bool
):
    assert is_valid_hostname_char(input_char) is expected_result

@pytest.mark.parametrize(
    "url_to_check, expected_status_code, expected_status_text",
    [
        ("https://google.com", 200, "OK"),
        (
            "https://fakesite123.org/notfound",
            404,
            "HTTP_ERROR (404)",
        ),
        (
            "http://httpbin.org/status/503",
            503,
            "HTTP_ERROR (503)",
        ),
        (
            "http://localhost:1",
            "CONNECTION_ERROR",
            "CONNECTION_ERROR",
        ),
        pytest.param(
            "https://pending.retries.tests",
            503,
            "HTTP_ERROR (503)",
            marks=(
                pytest.mark.xfail(
                    reason="Retry logic for 503 is not yet implemented."
                ),
                pytest.mark.api,
            ),
        ),
    ],
    ids=[
        "google_ok",
        "site_not_found",
        "server_error_503",
        "connection_error",
        "xfail_retry_case",
    ],
)
def test_various_url_statuses(
    url_to_check: str,
    expected_status_code: int,
    expected_status_text: str,
):
    status_code, status_text = check_url_status(url_to_check)
    assert status_code == expected_status_code
    assert status_text == expected_status_text
1 month ago Permalien
cluster icon
  • Handling Authentication : Handling Authentication APIs often require authentication to control access, rate limits, and auditing. Without authentication, requests to protected...
  • Working with CSV files : Working with CSV files CSV (Comma Separated Values) is a plain-text tabular format where each line is a row and fields are delimited (commonly by com...
  • Declarative Logging : Declarative Logging Configuration Declarative configuration separates setup from code, making it easier to maintain and adjust. Python’s logging.conf...
  • Generics typing : Introduction to Generics Generic types let you write reusable, type-safe functions and classes that work uniformly across different data types. They ...
  • Typing : Introduction Python is a dynamically typed language, meaning you can assign values to variables without declaring their types, and type checking happ...

Fixtures in Pytest/shaare/5ERODQ

  • python
  • python

Fixtures in Pytest

  • As tests grow more complex, repeating setup and cleanup steps makes tests harder to read and maintain.
  • Pytest fixtures allow centralizing shared setup and teardown logic, promoting DRY code.
  • Fixtures prepare resources or data before tests and can optionally clean up after tests complete.

What is a Fixture?

  • A fixture in Pytest is a function decorated with @pytest.fixture that provides a baseline environment or data for tests.
  • Fixtures can supply test data, manage the test environment (e.g., temporary files, mock services), and provide reusable resources (e.g., client objects).
  • Tests request fixtures by declaring them as function arguments, and Pytest handles executing the fixture and injecting its result.

Defining a Simple Fixture with @pytest.fixture

  • Use @pytest.fixture above a function to mark it as a fixture that can return or yield resources.
  • A fixture that returns a value runs its setup code, returns the value, and skips teardown logic.
  • A fixture that yields a value transforms into a generator: code before yield is setup, the yielded value goes to the test, and code after yield is teardown.

Using Fixtures in Test Functions

  • Tests receive fixture results by naming them as parameters; Pytest locates and executes matching fixtures automatically.
  • This approach removes boilerplate setup code from tests and keeps test functions concise.

Fixture Scope and Lifecycle

  • Fixture scope controls how often setup and teardown run: function (default), class, module, or session.
  • A function-scoped fixture runs for each test function; a session-scoped fixture runs only once for the entire test session.
  • Choosing the right scope balances resource isolation (function scope) against efficiency (session scope).

Fixture Teardown (Cleanup)

  • To ensure cleanup logic executes after tests, define fixtures with yield rather than return.
  • Code after yield always runs, even if the test fails or raises an error.
  • This pattern mimics a try...finally block, ensuring resources like temporary files or connections are properly released.

conftest.py: Sharing Fixtures

  • Defining fixtures in a conftest.py file makes them available across multiple test modules without explicit imports.
  • Placing conftest.py in a test directory or its parent enables automatic discovery of shared fixtures.
  • This structure keeps fixture definitions centralized and tests cleaner.
import pytest
from typing import Iterable

ManagedResource = dict[str, str]

@pytest.fixture
def managed_resource() -> Iterable[ManagedResource]:
    print("  [SHARED FIXTURE]: acquiring resource lock")
    resource = {"status": "lock_acquired"}
    yield resource
    print("  [SHARED FIXTURE]: releasing resource lock")
    resource["status"] = "lock_released"
1 month ago Permalien
cluster icon
  • For & While Loops : For & While Loops Python provides two main ways to repeat actions: for loops (for iterating over known sequences) and while loops (for repeating as lo...
  • Filesystem Operations : Filesystem Operations (os & shutil) DevOps scripts often need to create, delete, copy, and move files and directories as part of automation workflows...
  • Configuring Pytest : Configuring Pytest As you start using Pytest extensively, typing -v or -m on the command line every time becomes tedious. Centralize your defaults in...
  • Running External Commands with subprocess.run : Running External Commands with subprocess.run DevOps automation often requires invoking existing CLI tools or scripts to leverage their functionality...
  • Parametrized Tests : Parametrized Tests Introduction Often, we need to test the same logic with different inputs and outputs, such as validating various IP address or hos...

Pytest Markers/shaare/80i_nw

  • python
  • python

Pytest Markers

  • Markers are decorators (@pytest.mark.<markername>) applied to tests to attach metadata.
  • Built-in markers like skip, skipif, xfail, and parametrize provide predefined behaviors.
  • Custom markers (e.g., slow, integration, api) help categorize tests by project-specific criteria.
  • Applying markers allows Pytest (and plugins) to filter, select, or modify tests during collection and execution.

Skipping Tests Unconditionally: @pytest.mark.skip

  • The skip marker unconditionally prevents a test from running, useful when a feature is disabled or under refactor.
  • Skipped tests show an s in the summary along with the provided reason.
  • Use @pytest.mark.skip(reason="...") to disable tests without removing their code.

Skipping Tests Conditionally: @pytest.mark.skipif

  • The skipif marker skips tests only when a specified condition evaluates to true at collection time.
  • Conditions can be expressions like sys.platform != "linux" or checks for optional dependencies.
  • This enables platform-specific, version-specific, or resource-dependent test filtering.

Expected Failures: @pytest.mark.xfail

  • The xfail marker marks tests expected to fail due to known bugs or unimplemented features.
  • Expected failures are reported as XFAIL and don’t cause the suite to fail; unexpected passes are reported as XPASS.

Custom Markers and Registration

  • Custom markers (e.g., slow, api, integration) help organize and categorize tests by functionality or runtime.
  • Tests can have multiple markers for fine-grained control (e.g., @pytest.mark.api and @pytest.mark.integration).
  • To avoid warnings, register custom markers in pytest.ini or pyproject.toml under the markers option.

Running Tests by Marker (m option)

  • The -m <expression> CLI option selects tests matching a marker expression.
  • Expressions support logical operators: and, or, and negation with not.
  • Examples: pytest -m slow, pytest -m "not slow", pytest -m "api and integration".

Common Pitfalls & How to Avoid Them

  • Overusing skip hides failures; prefer xfail for known bugs to maintain visibility.
  • Complex skipif conditions reduce readability; delegate logic to helper functions when needed.
  • Typos in marker names create unregistered markers; register all custom markers to catch errors early.
  • Forgetting to register markers leads to warnings; always define marker descriptions in configuration files.
import pytest
import time

try:
    import some_optional_library  # type: ignore
except ModuleNotFoundError:
    some_optional_library = None
# Section: Skipping Tests Unconditionally: @pytest.mark.skip

@pytest.mark.skip(
    reason="Skipping experimental feature until completion."
)
def test_new_experimental_feature() -> None:
    assert False

# Section: Skipping Tests Conditionally: @pytest.mark.skipif

@pytest.mark.skipif(
    some_optional_library is None,
    reason="Requires 'some_optional_library' to be installed.",
)
def test_with_optional_dependency() -> None:
    print(
        f"Running tests that depends on an optional library..."
    )
    assert some_optional_library

# Section: Expected Failures: @pytest.mark.xfail

@pytest.mark.xfail(
    reason="Bug #123: Division by zero not handled properly."
)
def test_divide_by_zero() -> None:
    _division = 1 / 0
    assert False

@pytest.mark.xfail  # Add strict=True to make XPASS lead to a failure
def test_expected_to_fail() -> None:
    assert True

# Section: Custom Markers and Registration

@pytest.mark.slow
def test_very_long_computations() -> None:
    time.sleep(5)
    assert True

@pytest.mark.api
@pytest.mark.smoke
def test_user_creation() -> None:
    assert True

# Section: Running Tests by Marker (m option)
1 month ago Permalien
cluster icon
  • Logging to Files : Logging to Files Basic File Logging with FileHandler Use logging.FileHandler to write log records to a file. mode='a' (append) preserves existing log...
  • If / Elif / Else Logic : If / Elif / Else Logic Control the flow of scripts based on conditions using if, elif, and else. The if Statement An if statement executes a block of ...
  • For & While Loops : For & While Loops Python provides two main ways to repeat actions: for loops (for iterating over known sequences) and while loops (for repeating as lo...
  • Handling Authentication : Handling Authentication APIs often require authentication to control access, rate limits, and auditing. Without authentication, requests to protected...
  • Lambda Functions : Lambda Functions Python functions defined with def allow multiple statements, clear naming, and support for docstrings, making them ideal for complex...


(110)
1 / 6
Liens par page
  • 20
  • 50
  • 100
Filtrer par liens sans tag
Replier Replier tout Déplier Déplier tout Êtes-vous sûr de vouloir supprimer ce lien ? Êtes-vous sûr de vouloir supprimer ce tag ? Le gestionnaire de marque-pages personnel, minimaliste, et sans base de données par la communauté Shaarli