<?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: Richard Devers</title>
    <description>The latest articles on DEV Community by Richard Devers (@richarddevers).</description>
    <link>https://dev.to/richarddevers</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%2F8872%2Fe591df24-5b87-4526-b448-c57a855944a8.jpeg</url>
      <title>DEV Community: Richard Devers</title>
      <link>https://dev.to/richarddevers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/richarddevers"/>
    <language>en</language>
    <item>
      <title>K8s / Nginx simple trick</title>
      <dc:creator>Richard Devers</dc:creator>
      <pubDate>Fri, 07 Jan 2022 15:33:55 +0000</pubDate>
      <link>https://dev.to/richarddevers/k8s-nginx-small-trick-25fd</link>
      <guid>https://dev.to/richarddevers/k8s-nginx-small-trick-25fd</guid>
      <description>&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;I recently have been through a simple yet interesting use case in my job.&lt;/p&gt;

&lt;p&gt;For some reasons, network teams forbid developers computers to  access mongoDb database directly.&lt;/p&gt;

&lt;p&gt;Only the kubernetes platform have network access to the managed database service.&lt;/p&gt;

&lt;p&gt;Basically:&lt;br&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%2F43zmfk955ns1dap4axym.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%2F43zmfk955ns1dap4axym.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Looking a the previous drawing, you may see where this is going, developers can access the k8s cluster and the k8s cluster can access to the managed db service ^^...&lt;/p&gt;

&lt;p&gt;So... here is the plan:&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%2F29852mt3xf65pcth5fxp.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%2F29852mt3xf65pcth5fxp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, let's deploy a simple nginx k8s service, configured to stream tcp connection from the port 8080 to the desired ip:port. Then use a port forward to redirect connection &lt;/p&gt;

&lt;p&gt;Assuming your mondoDb listen on 100.101.102.103:27017&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: mongodb-proxy
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: mongodb-proxy
  ingress:
    - {}
  egress:
    - {}
  policyTypes:
    - Ingress
    - Egress

---

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-proxy
data:
  nginx.conf: |
    worker_processes  auto;
    error_log  /var/log/nginx/error.log notice;
    pid        /tmp/nginx.pid;


    stream {
        server {
            listen  8080 so_keepalive=on;
            proxy_connect_timeout 2s;
            proxy_pass    stream_backend;
            proxy_timeout 10m;
        }
        upstream stream_backend {
          server 100.101.102.103:27017;
        }

    }

    events {
        worker_connections  1024;
    }

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-proxy
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: "mongodb-proxy"
  template:
    metadata:
      labels:
        app.kubernetes.io/component: "mongodb-proxy"
    spec:
      serviceAccountName: default
      securityContext: {}
      containers:
        - name: mongodb-proxy
          volumeMounts:
            - name: mongodb-proxy
              mountPath: /etc/nginx
          securityContext:
            readOnlyRootFilesystem: false
            runAsGroup: 1000
            runAsNonRoot: true
            runAsUser: 1000
          image: "nginx/nginx-unprivileged"
          imagePullPolicy: Always
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
            # - name: https
            #   containerPort: 443
            #   protocol: TCP
          resources:
            limits:
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 250m
              memory: 256Mi
      volumes:
        - name: mongodb-proxy
          configMap:
            name: mongodb-proxy

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

&lt;/div&gt;



&lt;p&gt;First, deploy this k8s template.&lt;/p&gt;

&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the nginx config file is directly set within the template and put into the container using a configMap, thanks k8s.&lt;/li&gt;
&lt;li&gt;the network policy is way too large (too lazy to write it , sorry)&lt;/li&gt;
&lt;li&gt;the ngninx-unpriviled image have been used because of some security restrictions on our k8s cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now i just have to create a port-forward between my computer to the mongodb-proxy.&lt;/p&gt;

&lt;p&gt;It should be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward mongodb-proxy 8080:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(i didn't test it, i use &lt;a href="https://github.com/derailed/k9s" rel="noopener noreferrer"&gt;k9s&lt;/a&gt; to do that for me).&lt;/p&gt;

&lt;p&gt;Now i can access my db directly from my computer using localhost:8080&lt;/p&gt;

&lt;p&gt;using Firefox i got:&lt;br&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%2F3euzys65nywp2he4t9rk.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%2F3euzys65nywp2he4t9rk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This solution is very easy to perform, can be adapt to lots of other backend and hold in a single small helm file.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Python libraries for quality programming</title>
      <dc:creator>Richard Devers</dc:creator>
      <pubDate>Fri, 07 Jan 2022 14:39:25 +0000</pubDate>
      <link>https://dev.to/richarddevers/my-top-python-library-lej</link>
      <guid>https://dev.to/richarddevers/my-top-python-library-lej</guid>
      <description>&lt;h2&gt;
  
  
  pydantic
&lt;/h2&gt;

&lt;p&gt;Pydantic is a library owned by &lt;a href="https://github.com/samuelcolvin"&gt;Samuel Colvin&lt;/a&gt; which is an incredible developper. Go read his code, you'll learn.&lt;/p&gt;

&lt;p&gt;From the doc:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Data validation and settings management using python type annotations.&lt;br&gt;
pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid.&lt;br&gt;
Define how data should be in pure, canonical python; validate it with pydantic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basically, Pydantic class are supercharged dataclass.&lt;/p&gt;

&lt;p&gt;Data validation, on-fly complex custom validation and/or transformation, de/serialization with optional key, attribute alias , secret management and so more can be accomplished with it. Cherry on the cake, it's mypy and Pylance compatible.&lt;/p&gt;

&lt;p&gt;Just have a look at their &lt;a href="https://pydantic-docs.helpmanual.io/#using-pydantic"&gt;users&lt;/a&gt; (spoiler: The NSA, AWS, Microsoft etc..)&lt;/p&gt;

&lt;p&gt;Your application will be way more robust, you'll deliver way faster and you'll have a significant gain in serenity.&lt;/p&gt;

&lt;p&gt;It's an absolute must use, a master class.&lt;/p&gt;

&lt;h2&gt;
  
  
  fastapi
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/tiangolo"&gt;fastapi&lt;/a&gt; is another master class, this time by &lt;a href="https://github.com/tiangolo"&gt;Sebastián Ramírez&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the doc:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Fast: Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). One of the fastest Python frameworks available.
- Fast to code: Increase the speed to develop features by about 200% to 300%. *
- Fewer bugs: Reduce about 40% of human (developer) induced errors. *
- Intuitive: Great editor support. Completion everywhere. Less time debugging.
- Easy: Designed to be easy to use and learn. Less time reading docs.
- Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
- Robust: Get production-ready code. With automatic interactive documentation.
- Standards-based: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything is said. Fully async, based on Pydantic (of course!), easy to test, fast and so on... By far the best REST API framework i have worked with.&lt;/p&gt;

&lt;h2&gt;
  
  
  typer
&lt;/h2&gt;

&lt;p&gt;Another one by Sebastián Ramírez, &lt;a href="https://typer.tiangolo.com/"&gt;typer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the doc:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Intuitive to write: Great editor support. Completion everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.
- Easy to use: It's easy to use for the final users. Automatic help, and automatic completion for all shells.
- Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
- Start simple: The simplest example adds only 2 lines of code to your app: 1 import, 1 function call.
- Grow large: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Built on Pydantic, typer allow you to create simple CLI within minutes and complex one in a few hours.&lt;/p&gt;

&lt;p&gt;Easy to test, easy to build, another great one to simplify your life.&lt;/p&gt;

&lt;h2&gt;
  
  
  httpx
&lt;/h2&gt;

&lt;p&gt;In my opinion, &lt;a href="https://www.python-httpx.org/"&gt;httpx&lt;/a&gt; is the best http client so far. sync/async support and everything you'll ever need. Easy to use. A great One.&lt;/p&gt;

&lt;p&gt;httpx tests are easy to do using &lt;a href="https://lundberg.github.io/respx/"&gt;respx&lt;/a&gt;. You can mock it very simply, side_effect management etc..&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: datamodel-code-generator
&lt;/h2&gt;

&lt;p&gt;Ok so pydantic help you create powerfull class models?&lt;/p&gt;

&lt;p&gt;What if you don't even have to write them?&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://github.com/koxudaxi/datamodel-code-generator"&gt;datamodel-code-generator&lt;/a&gt; propose.&lt;/p&gt;

&lt;p&gt;You put a swagger file in input, you get a python module with every swagger models as pydantic class in it as output! Magic!&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Modern Python setup for quality development</title>
      <dc:creator>Richard Devers</dc:creator>
      <pubDate>Fri, 07 Jan 2022 11:41:46 +0000</pubDate>
      <link>https://dev.to/richarddevers/modern-python-setup-for-quality-development-59fb</link>
      <guid>https://dev.to/richarddevers/modern-python-setup-for-quality-development-59fb</guid>
      <description>&lt;p&gt;In this article, i'll show you what is my common python setup.&lt;/p&gt;

&lt;p&gt;Goals are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High quality code standard&lt;/li&gt;
&lt;li&gt;Respect of the python standard&lt;/li&gt;
&lt;li&gt;Dev experience quality&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;repeatability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The IDE&lt;/li&gt;
&lt;li&gt;Python versions&lt;/li&gt;
&lt;li&gt;Package and virtual environments&lt;/li&gt;
&lt;li&gt;Code linter/formatter&lt;/li&gt;
&lt;li&gt;Tests tools&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Pre-commit&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is entirely subjective :)&lt;/p&gt;

&lt;h2&gt;
  
  
  IDE: VSCode
&lt;/h2&gt;

&lt;p&gt;VSCode is a great IDE for python programming.&lt;/p&gt;

&lt;p&gt;One of his best feature is his extensibility though extensions.&lt;/p&gt;

&lt;p&gt;Here are some extensions i used:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the general development environment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remote-Container&lt;/strong&gt;: Open any folder or repository inside a Docker container and take advantage of Visual Studio Code's full feature set. Great to ensure every dev environment through a team are identical.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;: Python IntelliSense (Pylance), Linting, Debugging (multi-threaded, remote), Jupyter Notebooks, code formatting, refactoring, unit tests, and more. I don't use Jupyter so i cant talk about it. However Pylance is a great tool. Under the hood it used PyRights which is a super fast code analyzer (way faster than mypy!). Don't forget add this to your settings:&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%2Fub3p13tx1klovwgmbux7.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%2Fub3p13tx1klovwgmbux7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;vscode-icons&lt;/strong&gt;: Each folder type have his own well design icons. Big project with a lots of files are way more easy to understand with that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Window Color&lt;/strong&gt;: Automatically adds a unique color to each window's activityBar and titleBar. A project will always have the same color. Great when a teams works on multiple project, everybody see the same color.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitLens&lt;/strong&gt;: Now you can see who wrote that directly into the code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For data parsing/formatting/transformation...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's lots of extensions for that depending on your use case (docker, helm, etc...)&lt;/p&gt;

&lt;p&gt;I think these one are required by pretty much every project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better TOML&lt;/li&gt;
&lt;li&gt;change-case&lt;/li&gt;
&lt;li&gt;Code Spell checker&lt;/li&gt;
&lt;li&gt;JSON Tools&lt;/li&gt;
&lt;li&gt;XML Tools&lt;/li&gt;
&lt;li&gt;YAML&lt;/li&gt;
&lt;li&gt;vscode-base64&lt;/li&gt;
&lt;li&gt;Sort JSON objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Python versions: &lt;strong&gt;Pyenv&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/pyenv/pyenv" rel="noopener noreferrer"&gt;Pyenv&lt;/a&gt; is so far the best python versions manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python package and venv: &lt;strong&gt;Poetry&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://python-poetry.org/docs/" rel="noopener noreferrer"&gt;Poetry&lt;/a&gt; is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.&lt;/p&gt;

&lt;p&gt;Basically, it's pip under steroids. It works with the latest package file format &lt;em&gt;pyproject.toml&lt;/em&gt; . His dependencies and build system are very reliable. You can still export requirements.txt if necessary. Virtual environments works like a charms. Multiple python version too. It solve a lot of pain point. This is a must have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code linter/formatter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;flake8&lt;/strong&gt;: &lt;a href="https://github.com/PyCQA/flake8" rel="noopener noreferrer"&gt;Flake8&lt;/a&gt; is a wrapper around these tools:
PyFlakes
pycodestyle
Ned Batchelder's McCabe script&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flake8 runs all the tools by launching the single flake8 command. It displays the warnings in a per-file, merged output.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;black&lt;/strong&gt;: &lt;a href="https://github.com/psf/black" rel="noopener noreferrer"&gt;Black&lt;/a&gt; is the uncompromising Python code formatter. By using it, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for more important matters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blackened code looks the same regardless of the project you're reading. Formatting becomes transparent after a while and you can focus on the content instead.&lt;/p&gt;

&lt;p&gt;Black makes code review faster by producing the smallest diffs possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;isort&lt;/strong&gt;: &lt;a href="https://github.com/PyCQA/isort" rel="noopener noreferrer"&gt;isort&lt;/a&gt; your imports, so you don't have to.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  For the tests
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;pytest&lt;/strong&gt;: Python allow to write way less code than using directly unittest. Lots of good library handle it very well. Some library extend it to be even more efficient and user friendly (pytest-mock, pytest-freezegun, pytest-sugar...)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;nox&lt;/strong&gt;: The first point of nox is to run your tests into multiple environment (multiple python version). In my opinion way better than tox&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  For the documentation: &lt;strong&gt;Mkdocs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Mkdocs allow you to write documentation using markdown format. Really easy to use and integrate. You can easily integrate your documentation to your CI/CD pipeline for automatically test it  then deploy it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Pre-commit&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is a must have. &lt;a href="https://pre-commit.com/" rel="noopener noreferrer"&gt;pre-commit&lt;/a&gt; allow you to run multiple scripts (a.k.a pre-commit) before your commit validation. There's a big catalogue of builtin pre-commit. Some will modify files. Some will just return warning or errors. You can automatically perform a TONS of tests/validation before committing anything.&lt;/p&gt;

&lt;p&gt;This is basically a local CI pipeline run before the real one.&lt;/p&gt;

&lt;p&gt;Here is an example of one &lt;em&gt;.pre-commit-config.yaml&lt;/em&gt; config file i use, among others it will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sort your import automatically&lt;/li&gt;
&lt;li&gt;black will format your code&lt;/li&gt;
&lt;li&gt;flake8 will warn you about style issue&lt;/li&gt;
&lt;li&gt;Validate .gitlab-ci.yaml against my enterprise gitlab server.&lt;/li&gt;
&lt;li&gt;check style for bash script&lt;/li&gt;
&lt;li&gt;and so much more...
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.0.1
    hooks:
      - id: check-added-large-files
      - id: check-ast
      - id: check-builtin-literals
      - id: check-case-conflict
      - id: check-docstring-first
      - id: check-executables-have-shebangs
      - id: check-json
      - id: check-merge-conflict
      - id: check-symlinks
      - id: check-toml
      - id: check-vcs-permalinks
      - id: check-xml
      - id: check-yaml
        args: [--allow-multiple-documents]
      - id: debug-statements
      - id: detect-aws-credentials
        args: [--allow-missing-credentials]
      - id: destroyed-symlinks
      - id: end-of-file-fixer
      - id: fix-byte-order-marker
      - id: fix-encoding-pragma
        args: [--remove]
      - id: forbid-new-submodules
      - id: mixed-line-ending
        args: [--fix=auto]
      - id: name-tests-test
        args: [--django]
      - id: requirements-txt-fixer
      - id: trailing-whitespace
  - repo: local
    hooks:
      - id: black
        name: black
        entry: poetry run black
        language: system
        types: [python]
      - id: flake8
        name: flake8
        entry: poetry run flake8
        language: system
        types: [python]
  - repo: https://github.com/pycqa/isort
    rev: "5.9.1"
    hooks:
      - id: isort
        args:
          - --profile
          - black
          - --filter-files
  - repo: https://github.com/adrienverge/yamllint.git
    rev: v1.26.1
    hooks:
      - id: yamllint
        args: [-c=.yamllint.yaml]
  - repo: https://gitlab.com/devopshq/gitlab-ci-linter
    rev: v1.0.2
    hooks:
      - id: gitlab-ci-linter
        args:
          - "--server"
          - "https://your.gitlab.server" # Need env var GITLAB_PRIVATE_TOKEN with gitlab api read token
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v2.17.11
    hooks:
      - id: commitizen
        stages: [commit-msg]
  - repo: https://github.com/jumanjihouse/pre-commit-hooks
    rev: 2.1.5 # or specific git tag
    hooks:
      - id: forbid-binary
      - id: shellcheck
      - id: shfmt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;bandit&lt;/strong&gt;: &lt;a href="https://github.com/PyCQA/bandit" rel="noopener noreferrer"&gt;Bandit&lt;/a&gt; is a tool designed to find common security issues in Python code. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this Bandit processes each file, builds an AST from it, and runs appropriate plugins against the AST nodes. Once Bandit has finished scanning all the files it generates a report.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;safety&lt;/strong&gt;: &lt;a href="https://github.com/pyupio/safety" rel="noopener noreferrer"&gt;Safety&lt;/a&gt; checks your installed dependencies for known security vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default it uses the open Python vulnerability database Safety DB, but can be upgraded to use pyup.io's Safety API using the --key option.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;gitleaks&lt;/strong&gt;: &lt;a href="https://github.com/zricethezav/gitleaks" rel="noopener noreferrer"&gt;Gitleaks&lt;/a&gt; is a SAST tool for detecting and preventing hardcoded secrets like passwords, api keys, and tokens in git repos. Gitleaks is an easy-to-use, all-in-one solution for detecting secrets, past or present, in your code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Job is done but if someone have better alternative, i would try them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you leaned a thing or two in this article.&lt;/p&gt;

&lt;p&gt;Using these tools can help you falling in some common pitfall.&lt;/p&gt;

&lt;p&gt;Pylance warning &amp;amp; errors are great best practices teachers. Your code understanding and therefore quality will greatly progress understanding and correcting them.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>programming</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Python use case - Pagination</title>
      <dc:creator>Richard Devers</dc:creator>
      <pubDate>Thu, 06 Jan 2022 17:28:45 +0000</pubDate>
      <link>https://dev.to/richarddevers/python-use-case-pagination-3ij4</link>
      <guid>https://dev.to/richarddevers/python-use-case-pagination-3ij4</guid>
      <description>&lt;h2&gt;
  
  
  The use case
&lt;/h2&gt;

&lt;p&gt;A common use in development is to get some data from an external backend.&lt;/p&gt;

&lt;p&gt;For performance reason, most implements pagination.&lt;/p&gt;

&lt;p&gt;Let see how we can get all result from a backend.&lt;/p&gt;

&lt;p&gt;For these examples, i'll use &lt;a href="https://github.com/encode/httpx"&gt;httpx&lt;/a&gt; to perform the http operation. It's an excellent client, you should use it.&lt;/p&gt;

&lt;p&gt;Note that these are quick examples, not suitable for production environment (no pydantic, no security, no retry, no error management etc...)&lt;/p&gt;

&lt;p&gt;In my examples i only print the lenght of the results, however, feel free to do something more interesting ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The backend
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://api.instantwebtools.net/v1/passenger?page=0&amp;amp;size=10"&gt;https://api.instantwebtools.net/v1/passenger?page=0&amp;amp;size=10&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It provides a paginated API of a fake airline company.&lt;/p&gt;

&lt;p&gt;Result looks like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"totalPassengers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19675&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"totalPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1968&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5ff393986feae02b6c22b251"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deepanss"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"trips"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"airline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cathay Pacific"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hong Kong"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"logo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://upload.wikimedia.org/wikipedia/en/thumb/1/17/Cathay_Pacific_logo.svg/300px-Cathay_Pacific_logo.svg.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"slogan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Move Beyond"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"head_quaters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cathay City, Hong Kong International Airport, Chek Lap Kok, Hong Kong"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"www.cathaypacific.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"established"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1946"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"__v"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;em&gt;async&lt;/em&gt; implementation
&lt;/h2&gt;

&lt;p&gt;A common implementation would look like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;httpx&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_passengers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Getting page n°&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"https://api.instantwebtools.net/v1/passenger?page=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;size=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_passengers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;get_passengers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"totalPages"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"total result:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_all_passengers&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Output should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Getting page n°0
Getting page n°1
Getting page n°2
Getting page n°3
Getting page n°4
Getting page n°5
Getting page n°6
Getting page n°7
Getting page n°8
Getting page n°9
Getting page n°10
total result:110 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;em&gt;async for&lt;/em&gt; implementation
&lt;/h2&gt;

&lt;p&gt;This implementation use &lt;em&gt;async generator&lt;/em&gt; in order to use &lt;em&gt;async for&lt;/em&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;httpx&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_passengers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Getting page n°&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"https://api.instantwebtools.net/v1/passenger?page=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;size=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_passengers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncGenerator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;get_passengers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;passenger&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;passenger&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;response_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"totalPages"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_all_passengers_async_for&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;passenger&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;passenger&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;get_all_passengers&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"total result:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_all_passengers_async_for&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation is based on generator. Since the async &lt;em&gt;get_all_passengers&lt;/em&gt; method &lt;em&gt;yield&lt;/em&gt; a result, it become an &lt;em&gt;AsyncGenerator&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AsyncGenerator&lt;/em&gt; implements the &lt;em&gt;__aiter__&lt;/em&gt; special method, that's why you can perform an &lt;em&gt;async for&lt;/em&gt; on like in &lt;em&gt;get_all_passengers_async_for&lt;/em&gt; .&lt;/p&gt;

&lt;p&gt;In order to test it, you'll have to mock the &lt;em&gt;__aiter__&lt;/em&gt; attribute.&lt;/p&gt;

&lt;p&gt;Example from &lt;a href="https://github.com/python/cpython/blob/main/Doc/library/unittest.mock-examples.rst#id29"&gt;the official documentation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; mock = MagicMock()  # AsyncMock also works here
&amp;gt;&amp;gt;&amp;gt; mock.__aiter__.return_value = [1, 2, 3]
&amp;gt;&amp;gt;&amp;gt; async def main():
...     return [i async for i in mock]
...
&amp;gt;&amp;gt;&amp;gt; asyncio.run(main())
[1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you enjoy learning this article :)&lt;/p&gt;

&lt;p&gt;You have two way to handle pagination into your code, depending on your use case :)&lt;/p&gt;

</description>
      <category>python</category>
      <category>async</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Python import - The law of Demeter</title>
      <dc:creator>Richard Devers</dc:creator>
      <pubDate>Tue, 04 Jan 2022 10:15:51 +0000</pubDate>
      <link>https://dev.to/richarddevers/python-import-the-law-of-demeter-4gi5</link>
      <guid>https://dev.to/richarddevers/python-import-the-law-of-demeter-4gi5</guid>
      <description>&lt;h2&gt;
  
  
  The Demeter Law
&lt;/h2&gt;

&lt;p&gt;Python import can be a little tricky. The law of Demeter guideline and his applications to python import can help you mastering them and also writes more user-friendly, testable and reliable code.&lt;/p&gt;

&lt;p&gt;According to wikipedia, the law of Demeter (or principle of least knowledge) is a software developing guideline that can be summarized this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.&lt;/li&gt;
&lt;li&gt;Each unit should only talk to its friends; don't talk to strangers.&lt;/li&gt;
&lt;li&gt;Only talk to your immediate friends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we want to apply these to python import (the python module would be the unit), it would become something like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each module should only import public object of submodule, but only from the closest submodule. (aka "immediate friends")&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The method
&lt;/h2&gt;

&lt;p&gt;In order to accomplish that, the key is to declare explicitly in each module (though the _&lt;em&gt;init_&lt;/em&gt;.py) which object are exposed. Then these objects are accessible to the parent module folder, which can also re-expose them if necessary.&lt;/p&gt;

&lt;p&gt;The benefices of this method are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your _&lt;em&gt;init_&lt;/em&gt;.py files become some kind of "documentation" of which objects should be accessed or not from other modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You fully control your import system, which is a key to loose-coupling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The final user (other developper using your module) experience is enhanced, import are short and clear.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A downside is that it is more verbose.&lt;/p&gt;

&lt;h2&gt;
  
  
  First example
&lt;/h2&gt;

&lt;p&gt;Assuming this setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project
│   __main__.py
└───demeter
│   │   __init__.py
│   └───module1
│       │   __init__.py
│       │   code1.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/code1.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that setup, we can access directly MyClass1 class from _&lt;em&gt;main_&lt;/em&gt;.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# __main__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter.module1.code1&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MyClass1&lt;/span&gt;

&lt;span class="n"&gt;class1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MyClass1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, however this is a demeter's law violation: _&lt;em&gt;main_&lt;/em&gt;.py import  MyClass1 from  demeter/module1/code1.py which is not an "immediate friend".&lt;/p&gt;

&lt;p&gt;A good smell to detect it are long import. When applying the law of demeter, import are usually pretty short.&lt;/p&gt;

&lt;p&gt;A cleaner way to do that would be...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explicitly expose MyClass1 from module1 to upper level module:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# demeter/module1/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter.module1&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Re-expose it to the upper level:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use it
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# __main__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;_&lt;em&gt;main_&lt;/em&gt;.py&lt;/strong&gt; only have knowledge of the &lt;strong&gt;demeter&lt;/strong&gt; module and the &lt;strong&gt;demeter&lt;/strong&gt; module only have knowledge about the &lt;strong&gt;module1&lt;/strong&gt; module. The principe of least knowledge is respected&lt;/li&gt;
&lt;li&gt;modules (&lt;strong&gt;demeter&lt;/strong&gt; and &lt;strong&gt;module1&lt;/strong&gt;) explicitly expose what can be used from them(&lt;strong&gt;explicit is better than implicit&lt;/strong&gt;, &lt;a href="https://www.python.org/dev/peps/pep-0020/" rel="noopener noreferrer"&gt;https://www.python.org/dev/peps/pep-0020/&lt;/a&gt;). &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Second example
&lt;/h2&gt;

&lt;p&gt;Assuming this extension of the previous setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project
│   __main__.py
└───demeter
│   │   __init__.py
│   └───module1
│       │   __init__.py
│       │   code1.py
|       └───module2
│       │   __init__.py
│       │   code2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/module2/code2.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use MyClass2 in _&lt;em&gt;main_&lt;/em&gt;.py we would...&lt;/p&gt;

&lt;p&gt;Expose it to module1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/module2/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter.module1.module2&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;code2&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;code2&lt;/span&gt;

&lt;span class="n"&gt;MyClass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-expose it but this time from module1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter.module1&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter.module1&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;module2&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;module2&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;span class="n"&gt;MyClass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass2&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;span class="n"&gt;MyClass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass2&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Finally, use it from your _&lt;em&gt;main&lt;/em&gt;_.py:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# __main__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;demeter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;span class="n"&gt;MyClass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass2&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Whole module example
&lt;/h2&gt;

&lt;p&gt;The law of demeter can also be applied to whole module.&lt;/p&gt;

&lt;p&gt;The previous example could be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/code1.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/module2/code2.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/module2/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;  &lt;span class="n"&gt;demeter.module1.module2&lt;/span&gt;  &lt;span class="kn"&gt;import&lt;/span&gt;  &lt;span class="n"&gt;code2&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="n"&gt;code2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/module1/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;  &lt;span class="n"&gt;demeter.module1&lt;/span&gt;  &lt;span class="kn"&gt;import&lt;/span&gt;  &lt;span class="n"&gt;code1&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="n"&gt;code1&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;  &lt;span class="n"&gt;demeter.module1&lt;/span&gt;  &lt;span class="kn"&gt;import&lt;/span&gt;  &lt;span class="n"&gt;module2&lt;/span&gt;  &lt;span class="k"&gt;as&lt;/span&gt;  &lt;span class="n"&gt;module2&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# demeter/__init__.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;  &lt;span class="n"&gt;demeter&lt;/span&gt;  &lt;span class="kn"&gt;import&lt;/span&gt;  &lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# demeter/__main__.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;  &lt;span class="n"&gt;demeter&lt;/span&gt;

&lt;span class="n"&gt;module1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;demeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module1&lt;/span&gt;

&lt;span class="n"&gt;MyClass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass1&lt;/span&gt;
&lt;span class="n"&gt;MyClass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyClass2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This second method looks very similar to the bad practice example, isn't it?&lt;br&gt;
However, the key points are that every desired module and object are &lt;strong&gt;explicitly&lt;/strong&gt; exposed.&lt;/p&gt;

&lt;p&gt;So you still benefice the full control of your module system and you respect the principle of least knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  VSCode, Pylance, Pyrights
&lt;/h2&gt;

&lt;p&gt;If you use VSCode and Pylance (which use Pyrights under the hood),  this method will avoid you to have some &lt;a href="https://github.com/microsoft/pylance-release/blob/main/DIAGNOSTIC_SEVERITY_RULES.md#diagnostic-severity-rules" rel="noopener noreferrer"&gt;reportUnknownMemberType errors&lt;/a&gt;&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%2Fem33tfo8udnxi7tu6vvx.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%2Fem33tfo8udnxi7tu6vvx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you learned something reading this article (my first one uWu ^^).&lt;/p&gt;

&lt;p&gt;It's up to you to choose if you prefer expose full module or only object. I guess it depends on the context, the project, the people etc....&lt;/p&gt;

&lt;p&gt;Even if it look a little "too much" and require more code and more rigorous , these methods really enhance control and quality on the long run as well as deeply understanding (and thinking about ;) ) responsibility of every part of your code.&lt;/p&gt;

</description>
      <category>python</category>
      <category>import</category>
      <category>design</category>
      <category>guideline</category>
    </item>
  </channel>
</rss>
