Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ebba93e

Browse files
committedApr 22, 2025·
initial files
0 parents  commit ebba93e

31 files changed

+1667
-0
lines changed
 
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-FileCopyrightText: 2021 Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
Thank you for contributing! Before you submit a pull request, please read the following.
6+
7+
Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html
8+
9+
If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs
10+
11+
Before submitting the pull request, make sure you've run Pylint and Black locally on your code. You can do this manually or using pre-commit. Instructions are available here: https://adafru.it/check-your-code
12+
13+
Please remove all of this text before submitting. Include an explanation or list of changes included in your PR, as well as, if applicable, a link to any related issues.

‎.github/workflows/build.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: Build CI
6+
7+
on: [pull_request, push]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Run Build CI workflow
14+
uses: adafruit/workflows-circuitpython-libs/build@main
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-FileCopyrightText: 2021 Scott Shawcroft for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: Failure help text
6+
7+
on:
8+
workflow_run:
9+
workflows: ["Build CI"]
10+
types:
11+
- completed
12+
13+
jobs:
14+
post-help:
15+
runs-on: ubuntu-latest
16+
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }}
17+
steps:
18+
- name: Post comment to help
19+
uses: adafruit/circuitpython-action-library-ci-failed@v1

‎.github/workflows/release_gh.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: GitHub Release Actions
6+
7+
on:
8+
release:
9+
types: [published]
10+
11+
jobs:
12+
upload-release-assets:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Run GitHub Release CI workflow
16+
uses: adafruit/workflows-circuitpython-libs/release-gh@main
17+
with:
18+
github-token: ${{ secrets.GITHUB_TOKEN }}
19+
upload-url: ${{ github.event.release.upload_url }}

‎.github/workflows/release_pypi.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: PyPI Release Actions
6+
7+
on:
8+
release:
9+
types: [published]
10+
11+
jobs:
12+
upload-release-assets:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Run PyPI Release CI workflow
16+
uses: adafruit/workflows-circuitpython-libs/release-pypi@main
17+
with:
18+
pypi-username: ${{ secrets.pypi_username }}
19+
pypi-password: ${{ secrets.pypi_password }}

‎.gitignore

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# Do not include files and directories created by your personal work environment, such as the IDE
6+
# you use, except for those already listed here. Pull requests including changes to this file will
7+
# not be accepted.
8+
9+
# This .gitignore file contains rules for files generated by working with CircuitPython libraries,
10+
# including building Sphinx, testing with pip, and creating a virual environment, as well as the
11+
# MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs.
12+
13+
# If you find that there are files being generated on your machine that should not be included in
14+
# your git commit, you should create a .gitignore_global file on your computer to include the
15+
# files created by your personal setup. To do so, follow the two steps below.
16+
17+
# First, create a file called .gitignore_global somewhere convenient for you, and add rules for
18+
# the files you want to exclude from git commits.
19+
20+
# Second, configure Git to use the exclude file for all Git repositories by running the
21+
# following via commandline, replacing "path/to/your/" with the actual path to your newly created
22+
# .gitignore_global file:
23+
# git config --global core.excludesfile path/to/your/.gitignore_global
24+
25+
# CircuitPython-specific files
26+
*.mpy
27+
28+
# Python-specific files
29+
__pycache__
30+
*.pyc
31+
32+
# Sphinx build-specific files
33+
_build
34+
35+
# This file results from running `pip -e install .` in a local repository
36+
*.egg-info
37+
38+
# Virtual environment-specific files
39+
.env
40+
.venv
41+
42+
# MacOS-specific files
43+
*.DS_Store
44+
45+
# IDE-specific files
46+
.idea
47+
.vscode
48+
*~

‎.pre-commit-config.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
repos:
6+
- repo: https://github.com/pre-commit/pre-commit-hooks
7+
rev: v4.5.0
8+
hooks:
9+
- id: check-yaml
10+
- id: end-of-file-fixer
11+
- id: trailing-whitespace
12+
- repo: https://github.com/astral-sh/ruff-pre-commit
13+
rev: v0.3.4
14+
hooks:
15+
- id: ruff-format
16+
- id: ruff
17+
args: ["--fix"]
18+
- repo: https://github.com/fsfe/reuse-tool
19+
rev: v3.0.1
20+
hooks:
21+
- id: reuse

‎.readthedocs.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
# Read the Docs configuration file
6+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
7+
8+
# Required
9+
version: 2
10+
11+
sphinx:
12+
configuration: docs/conf.py
13+
14+
build:
15+
os: ubuntu-lts-latest
16+
tools:
17+
python: "3"
18+
19+
python:
20+
install:
21+
- requirements: docs/requirements.txt
22+
- requirements: requirements.txt

‎CODE_OF_CONDUCT.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2014 Coraline Ada Ehmke
3+
SPDX-FileCopyrightText: 2019-2021 Kattni Rembor for Adafruit Industries
4+
5+
SPDX-License-Identifier: CC-BY-4.0
6+
-->
7+
# Adafruit Community Code of Conduct
8+
9+
## Our Pledge
10+
11+
In the interest of fostering an open and welcoming environment, we as
12+
contributors and leaders pledge to making participation in our project and
13+
our community a harassment-free experience for everyone, regardless of age, body
14+
size, disability, ethnicity, gender identity and expression, level or type of
15+
experience, education, socio-economic status, nationality, personal appearance,
16+
race, religion, or sexual identity and orientation.
17+
18+
## Our Standards
19+
20+
We are committed to providing a friendly, safe and welcoming environment for
21+
all.
22+
23+
Examples of behavior that contributes to creating and maintaining a positive environment
24+
include:
25+
26+
* Be kind and courteous to others
27+
* Using welcoming and inclusive language
28+
* Respecting the identity of every community member, including asking for their
29+
pronouns if uncertain
30+
* Being respectful of differing viewpoints and experiences
31+
* Collaborating with other community members
32+
* Providing desired assistance and knowledge to other community members
33+
* Being open to new information and ideas
34+
* Gracefully accepting constructive criticism
35+
* Focusing on what is best for the community
36+
* Showing empathy towards other community members
37+
38+
Examples of unacceptable behavior by community members include:
39+
40+
* The use of sexualized language or imagery and sexual attention or advances
41+
* The use of inappropriate images, including in a community member's avatar
42+
* The use of inappropriate language or profanity, including in a community member's nickname
43+
* Any spamming, flaming, baiting or other attention-stealing behavior
44+
* Excessive or unwelcome helping; answering outside the scope of the question
45+
asked
46+
* Discussion or promotion of activities or projects that intend or pose a risk of
47+
significant harm
48+
* Trolling, insulting/derogatory comments, and attacks of any nature (including,
49+
but not limited to, personal or political attacks)
50+
* Promoting or spreading disinformation, lies, or conspiracy theories against
51+
a person, group, organisation, project, or community
52+
* Public or private harassment
53+
* Publishing others' private information, such as a physical or electronic
54+
address, without explicit permission
55+
* Engaging in behavior that creates an unwelcoming or uninclusive environment
56+
* Other conduct which could reasonably be considered inappropriate
57+
58+
The Adafruit Community welcomes everyone and strives to create a safe space for all. It is built
59+
around sharing and contributing to technology. We encourage discussing your thoughts, experiences,
60+
and feelings within the scope of the community. However, there are topics that can sometimes stray
61+
from that scope, and can lead to hurting others and create an unwelcoming, uninclusive environment.
62+
63+
Examples of discussion topics that have been known to stray outside the scope of the Adafruit
64+
Community include, but are not limited to:
65+
66+
* Discussions regarding religion and related topics
67+
* Discussions regarding politics and related topics
68+
69+
The goal of the standards and moderation guidelines outlined here is to build
70+
and maintain a respectful community. We ask that you don’t just aim to be
71+
"technically unimpeachable", but rather try to be your best self.
72+
73+
We value many things beyond technical expertise, including collaboration and
74+
supporting others within our community. Providing a positive experience for
75+
other community members can have a much more significant impact than simply
76+
providing the correct answer.
77+
78+
## Our Responsibilities
79+
80+
Project leaders are responsible for clarifying the standards of acceptable
81+
behavior and are expected to take appropriate and fair corrective action in
82+
response to any instances of unacceptable behavior.
83+
84+
Project leaders have the right and responsibility to remove, edit, or
85+
reject messages, comments, commits, code, issues, and other contributions
86+
that are not aligned to this Code of Conduct, or to ban temporarily or
87+
permanently any community member for other behaviors that they deem
88+
inappropriate, threatening, offensive, or harmful.
89+
90+
## Moderation
91+
92+
Instances of behaviors that violate the Adafruit Community Code of Conduct
93+
may be reported by any member of the community. Community members are
94+
encouraged to report these situations, including situations they witness
95+
involving other community members.
96+
97+
You may report in the following ways:
98+
99+
In any situation, you may email <support@adafruit.com>.
100+
101+
On the Adafruit Discord, you may send an open message from any channel
102+
to all Community Moderators by tagging @community moderators. You may
103+
also send an open message from the #help-with-community channel, or a
104+
direct message to any Community Moderator.
105+
106+
The source of email and direct message reports will be kept confidential.
107+
108+
In situations on Discord where the issue is particularly offensive, possibly
109+
illegal, requires immediate action, or violates the Discord terms of service,
110+
you should also report the message directly to [Discord](https://discord.com/safety).
111+
112+
These are the steps for upholding our community’s standards of conduct.
113+
114+
1. Any member of the community may report any situation that violates the
115+
Adafruit Community Code of Conduct. All reports will be reviewed and
116+
investigated.
117+
2. If the behavior is a severe violation, the community member who
118+
committed the violation may be banned immediately, without warning.
119+
3. Otherwise, moderators will first respond to such behavior with a warning.
120+
4. Moderators follow a soft "three strikes" policy - the community member may
121+
be given another chance, if they are receptive to the warning and change their
122+
behavior.
123+
5. If the community member is unreceptive or unreasonable when warned by a
124+
moderator, or the warning goes unheeded, they may be banned for a first or
125+
second offense. Repeated offenses will result in the community member being
126+
banned.
127+
6. Disciplinary actions (warnings, bans, etc) for Code of Conduct violations apply
128+
to the platform where the violation occurred. However, depending on the severity
129+
of the violation, the disciplinary action may be applied across Adafruit's other
130+
community platforms. For example, a severe violation on the Adafruit Discord
131+
server may result in a ban on not only the Adafruit Discord server, but also on
132+
the Adafruit GitHub organisation, Adafruit Forums, Adafruit Twitter, etc.
133+
134+
## Scope
135+
136+
This Code of Conduct and the enforcement policies listed above apply to all
137+
Adafruit Community venues. This includes but is not limited to any community
138+
spaces (both public and private), the entire Adafruit Discord server, and
139+
Adafruit GitHub repositories. Examples of Adafruit Community spaces include
140+
but are not limited to meet-ups, audio chats on the Adafruit Discord, or
141+
interaction at a conference.
142+
143+
This Code of Conduct applies both within project spaces and in public spaces
144+
when an individual is representing the project or its community. As a community
145+
member, you are representing our community, and are expected to behave
146+
accordingly.
147+
148+
## Attribution
149+
150+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
151+
version 1.4, available on [contributor-covenant.org](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html),
152+
and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
153+
154+
For other projects adopting the Adafruit Community Code of
155+
Conduct, please contact the maintainers of those projects for enforcement.
156+
If you wish to use this code of conduct for your own project, consider
157+
explicitly mentioning your moderation policy or making a copy with your
158+
own moderation policy so as to avoid confusion.

‎LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2025 Tim Cocks for Adafruit Industries
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎LICENSES/CC-BY-4.0.txt

Lines changed: 324 additions & 0 deletions
Large diffs are not rendered by default.

‎LICENSES/MIT.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
MIT License Copyright (c) <year> <copyright holders>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice (including the next
11+
paragraph) shall be included in all copies or substantial portions of the
12+
Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
17+
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19+
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

‎LICENSES/Unlicense.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or distribute
4+
this software, either in source code form or as a compiled binary, for any
5+
purpose, commercial or non-commercial, and by any means.
6+
7+
In jurisdictions that recognize copyright laws, the author or authors of this
8+
software dedicate any and all copyright interest in the software to the public
9+
domain. We make this dedication for the benefit of the public at large and
10+
to the detriment of our heirs and successors. We intend this dedication to
11+
be an overt act of relinquishment in perpetuity of all present and future
12+
rights to this software under copyright law.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
17+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
19+
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information,
20+
please refer to <https://unlicense.org/>

‎README.rst

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
Introduction
2+
============
3+
4+
5+
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-pathlib/badge/?version=latest
6+
:target: https://docs.circuitpython.org/projects/pathlib/en/latest/
7+
:alt: Documentation Status
8+
9+
10+
.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg
11+
:target: https://adafru.it/discord
12+
:alt: Discord
13+
14+
15+
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_Pathlib/workflows/Build%20CI/badge.svg
16+
:target: https://github.com/adafruit/Adafruit_CircuitPython_Pathlib/actions
17+
:alt: Build Status
18+
19+
20+
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
21+
:target: https://github.com/astral-sh/ruff
22+
:alt: Code Style: Ruff
23+
24+
Subset of the CPython module pathlib
25+
26+
27+
Dependencies
28+
=============
29+
This driver depends on:
30+
31+
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
32+
33+
Please ensure all dependencies are available on the CircuitPython filesystem.
34+
This is easily achieved by downloading
35+
`the Adafruit library and driver bundle <https://circuitpython.org/libraries>`_
36+
or individual libraries can be installed using
37+
`circup <https://github.com/adafruit/circup>`_.
38+
39+
40+
Installing from PyPI
41+
=====================
42+
43+
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
44+
PyPI <https://pypi.org/project/adafruit-circuitpython-pathlib/>`_.
45+
To install for current user:
46+
47+
.. code-block:: shell
48+
49+
pip3 install adafruit-circuitpython-pathlib
50+
51+
To install system-wide (this may be required in some cases):
52+
53+
.. code-block:: shell
54+
55+
sudo pip3 install adafruit-circuitpython-pathlib
56+
57+
To install in a virtual environment in your current project:
58+
59+
.. code-block:: shell
60+
61+
mkdir project-name && cd project-name
62+
python3 -m venv .venv
63+
source .env/bin/activate
64+
pip3 install adafruit-circuitpython-pathlib
65+
66+
Installing to a Connected CircuitPython Device with Circup
67+
==========================================================
68+
69+
Make sure that you have ``circup`` installed in your Python environment.
70+
Install it with the following command if necessary:
71+
72+
.. code-block:: shell
73+
74+
pip3 install circup
75+
76+
With ``circup`` installed and your CircuitPython device connected use the
77+
following command to install:
78+
79+
.. code-block:: shell
80+
81+
circup install adafruit_pathlib
82+
83+
Or the following command to update an existing version:
84+
85+
.. code-block:: shell
86+
87+
circup update
88+
89+
Usage Example
90+
=============
91+
92+
.. code-block:: python
93+
94+
import adafruit_pathlib
95+
96+
97+
def print_directory_tree(path: adafruit_pathlib.Path, prefix: str = ""):
98+
"""Recursively prints an ASCII tree of the given directory."""
99+
if not path.is_dir():
100+
print(f"{path} is not a directory.")
101+
return
102+
103+
entries = sorted(path.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))
104+
for index, entry in enumerate(entries):
105+
connector = "├── " if index < len(entries) - 1 else "└── "
106+
print(f"{prefix}{connector}{entry.name}")
107+
if entry.is_dir():
108+
extension = "" if index < len(entries) - 1 else " "
109+
print_directory_tree(entry, prefix + extension)
110+
111+
112+
dir_path = adafruit_pathlib.Path("/lib")
113+
114+
print_directory_tree(dir_path)
115+
116+
117+
Documentation
118+
=============
119+
API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/pathlib/en/latest/>`_.
120+
121+
For information on building library documentation, please check out
122+
`this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
123+
124+
Contributing
125+
============
126+
127+
Contributions are welcome! Please read our `Code of Conduct
128+
<https://github.com/adafruit/Adafruit_CircuitPython_Pathlib/blob/HEAD/CODE_OF_CONDUCT.md>`_
129+
before contributing to help this project stay welcoming.

‎README.rst.license

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
SPDX-License-Identifier: MIT

‎adafruit_pathlib.py

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2013, 2014 micropython-lib contributors
2+
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
#
4+
# SPDX-License-Identifier: MIT
5+
"""
6+
`adafruit_pathlib`
7+
================================================================================
8+
9+
Subset of the CPython module pathlib
10+
11+
12+
* Author(s): micropython-lib contributors, Tim Cocks
13+
14+
Implementation Notes
15+
--------------------
16+
17+
**Software and Dependencies:**
18+
19+
* Adafruit CircuitPython firmware for the supported boards:
20+
https://circuitpython.org/downloads
21+
22+
"""
23+
24+
# imports
25+
26+
__version__ = "0.0.0+auto.0"
27+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Pathlib.git"
28+
29+
import errno
30+
import os
31+
32+
import storage
33+
from micropython import const
34+
35+
_SEP = const("/")
36+
37+
38+
def _mode_if_exists(path):
39+
try:
40+
return os.stat(path)[0]
41+
except OSError as e:
42+
if e.errno == errno.ENOENT:
43+
return 0
44+
raise e
45+
46+
47+
def _clean_segment(segment):
48+
segment = str(segment)
49+
if not segment:
50+
return "."
51+
segment = segment.rstrip(_SEP)
52+
if not segment:
53+
return _SEP
54+
while True:
55+
no_double = segment.replace(_SEP + _SEP, _SEP)
56+
if no_double == segment:
57+
break
58+
segment = no_double
59+
return segment
60+
61+
62+
class Path:
63+
def __init__(self, *segments):
64+
segments_cleaned = []
65+
for segment in segments:
66+
segment = _clean_segment(segment) # noqa: PLW2901, for loop var overwritten
67+
if segment[0] == _SEP:
68+
segments_cleaned = [segment]
69+
elif segment == ".":
70+
continue
71+
else:
72+
segments_cleaned.append(segment)
73+
74+
self._path = _clean_segment(_SEP.join(segments_cleaned))
75+
76+
def __truediv__(self, other):
77+
return Path(self._path, str(other))
78+
79+
def __rtruediv__(self, other):
80+
return Path(other, self._path)
81+
82+
def __repr__(self):
83+
return f'{type(self).__name__}("{self._path}")'
84+
85+
def __str__(self):
86+
return self._path
87+
88+
def __eq__(self, other):
89+
return self.absolute() == Path(other).absolute()
90+
91+
def absolute(self):
92+
"""
93+
Absolute path
94+
"""
95+
path = self._path
96+
cwd = os.getcwd()
97+
if not path or path == ".":
98+
return cwd
99+
if path[0] == _SEP:
100+
return path
101+
return _SEP + path if cwd == _SEP else cwd + _SEP + path
102+
103+
def resolve(self):
104+
"""
105+
Absolute path
106+
"""
107+
return self.absolute()
108+
109+
def open(self, mode="r", encoding=None):
110+
"""
111+
Open a file from the path.
112+
:param mode: The mode to open the file in
113+
:param encoding: The encoding to use
114+
:return: an opened file handle
115+
"""
116+
return open(self._path, mode, encoding=encoding)
117+
118+
def exists(self):
119+
"""
120+
:return: True if the path exists
121+
"""
122+
return bool(_mode_if_exists(self._path))
123+
124+
def mkdir(self, parents=False, exist_ok=False):
125+
"""
126+
Make a directory
127+
:param parents:
128+
:param exist_ok:
129+
:return:
130+
"""
131+
try:
132+
os.mkdir(self._path)
133+
return
134+
except OSError as e:
135+
if e.errno == errno.EEXIST and exist_ok:
136+
return
137+
elif e.errno == errno.ENOENT and parents:
138+
pass # handled below
139+
else:
140+
raise e
141+
142+
segments = self._path.split(_SEP)
143+
progressive_path = ""
144+
if not segments[0]:
145+
segments = segments[1:]
146+
progressive_path = _SEP
147+
for segment in segments:
148+
progressive_path += _SEP + segment
149+
try:
150+
os.mkdir(progressive_path)
151+
except OSError as e:
152+
if e.errno != errno.EEXIST:
153+
raise e
154+
155+
def is_dir(self):
156+
"""
157+
:return: True if the path is a directory.
158+
"""
159+
return bool(_mode_if_exists(self._path) & 0x4000)
160+
161+
def is_file(self):
162+
"""
163+
:return: True if the path is a file.
164+
"""
165+
return bool(_mode_if_exists(self._path) & 0x8000)
166+
167+
@staticmethod
168+
def _get_mount_for(path):
169+
path = path.rstrip("/")
170+
if path[0] != "/":
171+
path = os.getcwd() + "/" + path
172+
while len(path) > 0:
173+
try:
174+
return storage.getmount(path)
175+
except OSError:
176+
pos = path.rfind("/")
177+
path = path[:pos]
178+
return None
179+
180+
def _glob(self, path, pattern, recursive):
181+
# Currently only supports a single "*" pattern.
182+
n_wildcards = pattern.count("*")
183+
n_single_wildcards = pattern.count("?")
184+
185+
if n_single_wildcards:
186+
raise NotImplementedError("? single wildcards not implemented.")
187+
188+
if n_wildcards == 0:
189+
raise ValueError
190+
elif n_wildcards > 1:
191+
raise NotImplementedError("Multiple * wildcards not implemented.")
192+
193+
prefix, suffix = pattern.split("*")
194+
path_mount = Path._get_mount_for(path)
195+
for name, mode, *_ in path_mount.ilistdir(path):
196+
full_path = path + _SEP + name
197+
if name.startswith(prefix) and name.endswith(suffix):
198+
yield full_path
199+
if recursive and mode & 0x4000: # is_dir
200+
yield from self._glob(full_path, pattern, recursive=recursive)
201+
202+
def glob(self, pattern):
203+
"""Iterate over this subtree and yield all existing files (of any
204+
kind, including directories) matching the given relative pattern.
205+
206+
Currently only supports a single "*" pattern.
207+
"""
208+
return self._glob(self._path, pattern, recursive=False)
209+
210+
def rglob(self, pattern):
211+
"""
212+
Recursive glob
213+
"""
214+
return self._glob(self._path, pattern, recursive=True)
215+
216+
def stat(self):
217+
"""
218+
File status
219+
:return: the file_status object for the path
220+
"""
221+
return os.stat(self._path)
222+
223+
def read_bytes(self):
224+
"""
225+
Read bytes from the file at the path
226+
:return: the bytes read
227+
"""
228+
with open(self._path, "rb") as f:
229+
return f.read()
230+
231+
def read_text(self, encoding=None):
232+
"""
233+
Read text from the file at the path
234+
:param encoding: encoding to use
235+
:return: the text read
236+
"""
237+
with open(self._path, encoding=encoding) as f:
238+
return f.read()
239+
240+
def rename(self, target):
241+
"""
242+
Rename the file at the path
243+
:param target: new name
244+
:return: None
245+
"""
246+
os.rename(self._path, target)
247+
248+
def rmdir(self):
249+
"""
250+
Remove the directory at the path
251+
:return: None
252+
"""
253+
os.rmdir(self._path)
254+
255+
def touch(self, exist_ok=True):
256+
"""
257+
Touch the file at the path
258+
"""
259+
if self.exists():
260+
if exist_ok:
261+
return # TODO: should update timestamp
262+
else:
263+
# In lieue of FileExistsError
264+
raise OSError(errno.EEXIST)
265+
with open(self._path, "w"):
266+
pass
267+
268+
def unlink(self, missing_ok=False):
269+
"""
270+
Remove (delete) the file at the path. The name unlink was traditionally
271+
used by Unix.
272+
"""
273+
try:
274+
os.unlink(self._path)
275+
except OSError as e:
276+
if not (missing_ok and e.errno == errno.ENOENT):
277+
raise e
278+
279+
def write_bytes(self, data):
280+
"""
281+
Write bytes to the file at the path
282+
:param data: the bytes to write
283+
:return: None
284+
"""
285+
with open(self._path, "wb") as f:
286+
f.write(data)
287+
288+
def write_text(self, data, encoding=None):
289+
"""
290+
Write text to the file at the path
291+
:param data: the text to write
292+
:param encoding: the encoding to use
293+
:return: None
294+
"""
295+
with open(self._path, "w", encoding=encoding) as f:
296+
f.write(data)
297+
298+
def with_suffix(self, suffix):
299+
"""
300+
:param suffix: the new suffix to use
301+
:return: Return a new path with the suffix changed.
302+
"""
303+
index = -len(self.suffix) or None
304+
return Path(self._path[:index] + suffix)
305+
306+
@property
307+
def stem(self):
308+
"""
309+
310+
:return: The stem of the path
311+
"""
312+
return self.name.rsplit(".", 1)[0]
313+
314+
@property
315+
def parent(self):
316+
"""
317+
The parent of the path
318+
"""
319+
tokens = self._path.rsplit(_SEP, 1)
320+
if len(tokens) == 2:
321+
if not tokens[0]:
322+
tokens[0] = _SEP
323+
return Path(tokens[0])
324+
return Path(".")
325+
326+
@property
327+
def name(self):
328+
"""
329+
:return: The name of the file at the path
330+
"""
331+
return self._path.rsplit(_SEP, 1)[-1]
332+
333+
@property
334+
def suffix(self):
335+
"""
336+
The suffix of the file at the path
337+
"""
338+
elems = self._path.rsplit(".", 1)
339+
return "" if len(elems) == 1 else "." + elems[1]
340+
341+
def iterdir(self):
342+
"""Iterate over the files in this directory.
343+
344+
Yields Path objects for the contents of the directory.
345+
Does not yield entries for '.' and '..'.
346+
347+
Raises:
348+
OSError: If self.is_dir() is False.
349+
"""
350+
if not self.is_dir():
351+
raise OSError(errno.ENOTDIR, f"Not a directory: {self._path}")
352+
print(f"self._path: {self._path}")
353+
for name in os.listdir(self._path):
354+
print(f"name: {name}")
355+
yield Path(self._path, name)
356+
357+
def __hash__(self):
358+
return hash(self._path)

‎docs/_static/favicon.ico

4.31 KB
Binary file not shown.

‎docs/_static/favicon.ico.license

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SPDX-FileCopyrightText: 2018 Phillip Torrone for Adafruit Industries
2+
3+
SPDX-License-Identifier: CC-BY-4.0

‎docs/api.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
.. If you created a package, create one automodule per module in the package.
3+
4+
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
5+
.. use this format as the module name: "adafruit_foo.foo"
6+
7+
API Reference
8+
#############
9+
10+
.. automodule:: adafruit_pathlib
11+
:members:

‎docs/api.rst.license

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
4+
SPDX-License-Identifier: MIT

‎docs/conf.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import datetime
6+
import os
7+
import sys
8+
9+
sys.path.insert(0, os.path.abspath(".."))
10+
11+
# -- General configuration ------------------------------------------------
12+
13+
# Add any Sphinx extension module names here, as strings. They can be
14+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
15+
# ones.
16+
extensions = [
17+
"sphinx.ext.autodoc",
18+
"sphinxcontrib.jquery",
19+
"sphinx.ext.intersphinx",
20+
"sphinx.ext.napoleon",
21+
"sphinx.ext.todo",
22+
]
23+
24+
# TODO: Please Read!
25+
# Uncomment the below if you use native CircuitPython modules such as
26+
# digitalio, micropython and busio. List the modules you use. Without it, the
27+
# autodoc module docs will fail to generate with a warning.
28+
autodoc_mock_imports = ["storage"]
29+
30+
autodoc_preserve_defaults = True
31+
32+
intersphinx_mapping = {
33+
"python": ("https://docs.python.org/3", None),
34+
"CircuitPython": ("https://docs.circuitpython.org/en/latest/", None),
35+
}
36+
37+
# Show the docstring from both the class and its __init__() method.
38+
autoclass_content = "both"
39+
40+
# Add any paths that contain templates here, relative to this directory.
41+
templates_path = ["_templates"]
42+
43+
source_suffix = ".rst"
44+
45+
# The master toctree document.
46+
master_doc = "index"
47+
48+
# General information about the project.
49+
project = "Adafruit CircuitPython Pathlib Library"
50+
creation_year = "2025"
51+
current_year = str(datetime.datetime.now().year)
52+
year_duration = (
53+
current_year if current_year == creation_year else creation_year + " - " + current_year
54+
)
55+
copyright = year_duration + " Tim Cocks"
56+
author = "Tim Cocks"
57+
58+
# The version info for the project you're documenting, acts as replacement for
59+
# |version| and |release|, also used in various other places throughout the
60+
# built documents.
61+
#
62+
# The short X.Y version.
63+
version = "1.0"
64+
# The full version, including alpha/beta/rc tags.
65+
release = "1.0"
66+
67+
# The language for content autogenerated by Sphinx. Refer to documentation
68+
# for a list of supported languages.
69+
#
70+
# This is also used if you do content translation via gettext catalogs.
71+
# Usually you set "language" from the command line for these cases.
72+
language = "en"
73+
74+
# List of patterns, relative to source directory, that match files and
75+
# directories to ignore when looking for source files.
76+
# This patterns also effect to html_static_path and html_extra_path
77+
exclude_patterns = [
78+
"_build",
79+
"Thumbs.db",
80+
".DS_Store",
81+
".env",
82+
"CODE_OF_CONDUCT.md",
83+
]
84+
85+
# The reST default role (used for this markup: `text`) to use for all
86+
# documents.
87+
#
88+
default_role = "any"
89+
90+
# If true, '()' will be appended to :func: etc. cross-reference text.
91+
#
92+
add_function_parentheses = True
93+
94+
# The name of the Pygments (syntax highlighting) style to use.
95+
pygments_style = "sphinx"
96+
97+
# If true, `todo` and `todoList` produce output, else they produce nothing.
98+
todo_include_todos = False
99+
100+
# If this is True, todo emits a warning for each TODO entries. The default is False.
101+
todo_emit_warnings = True
102+
103+
napoleon_numpy_docstring = False
104+
105+
# -- Options for HTML output ----------------------------------------------
106+
107+
# The theme to use for HTML and HTML Help pages. See the documentation for
108+
# a list of builtin themes.
109+
#
110+
import sphinx_rtd_theme
111+
112+
html_theme = "sphinx_rtd_theme"
113+
114+
# Add any paths that contain custom static files (such as style sheets) here,
115+
# relative to this directory. They are copied after the builtin static files,
116+
# so a file named "default.css" will overwrite the builtin "default.css".
117+
html_static_path = ["_static"]
118+
119+
# The name of an image file (relative to this directory) to use as a favicon of
120+
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
121+
# pixels large.
122+
#
123+
html_favicon = "_static/favicon.ico"
124+
125+
# Output file base name for HTML help builder.
126+
htmlhelp_basename = "Adafruit_CircuitPython_Pathlib_Librarydoc"
127+
128+
# -- Options for LaTeX output ---------------------------------------------
129+
130+
latex_elements = {
131+
# The paper size ('letterpaper' or 'a4paper').
132+
# 'papersize': 'letterpaper',
133+
# The font size ('10pt', '11pt' or '12pt').
134+
# 'pointsize': '10pt',
135+
# Additional stuff for the LaTeX preamble.
136+
# 'preamble': '',
137+
# Latex figure (float) alignment
138+
# 'figure_align': 'htbp',
139+
}
140+
141+
# Grouping the document tree into LaTeX files. List of tuples
142+
# (source start file, target name, title,
143+
# author, documentclass [howto, manual, or own class]).
144+
latex_documents = [
145+
(
146+
master_doc,
147+
"Adafruit_CircuitPython_Pathlib_Library.tex",
148+
"Adafruit CircuitPython Pathlib Library Documentation",
149+
author,
150+
"manual",
151+
),
152+
]
153+
154+
# -- Options for manual page output ---------------------------------------
155+
156+
# One entry per manual page. List of tuples
157+
# (source start file, name, description, authors, manual section).
158+
man_pages = [
159+
(
160+
master_doc,
161+
"Adafruit_CircuitPython_Pathlib_Library",
162+
"Adafruit CircuitPython Pathlib Library Documentation",
163+
[author],
164+
1,
165+
),
166+
]
167+
168+
# -- Options for Texinfo output -------------------------------------------
169+
170+
# Grouping the document tree into Texinfo files. List of tuples
171+
# (source start file, target name, title, author,
172+
# dir menu entry, description, category)
173+
texinfo_documents = [
174+
(
175+
master_doc,
176+
"Adafruit_CircuitPython_Pathlib_Library",
177+
"Adafruit CircuitPython Pathlib Library Documentation",
178+
author,
179+
"Adafruit_CircuitPython_Pathlib_Library",
180+
"One line description of project.",
181+
"Miscellaneous",
182+
),
183+
]

‎docs/examples.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Simple test
2+
------------
3+
4+
Ensure your device works with this simple test.
5+
6+
.. literalinclude:: ../examples/pathlib_simpletest.py
7+
:caption: examples/pathlib_simpletest.py
8+
:linenos:

‎docs/examples.rst.license

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
4+
SPDX-License-Identifier: MIT

‎docs/index.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
.. include:: ../README.rst
3+
4+
Table of Contents
5+
=================
6+
7+
.. toctree::
8+
:maxdepth: 4
9+
:hidden:
10+
11+
self
12+
13+
.. toctree::
14+
:caption: Examples
15+
16+
examples
17+
18+
.. toctree::
19+
:caption: API Reference
20+
:maxdepth: 3
21+
22+
api
23+
24+
.. toctree::
25+
:caption: Tutorials
26+
27+
.. toctree::
28+
:caption: Related Products
29+
30+
.. toctree::
31+
:caption: Other Links
32+
33+
Download from GitHub <https://github.com/adafruit/Adafruit_CircuitPython_Pathlib/releases/latest>
34+
Download Library Bundle <https://circuitpython.org/libraries>
35+
CircuitPython Reference Documentation <https://docs.circuitpython.org>
36+
CircuitPython Support Forum <https://forums.adafruit.com/viewforum.php?f=60>
37+
Discord Chat <https://adafru.it/discord>
38+
Adafruit Learning System <https://learn.adafruit.com>
39+
Adafruit Blog <https://blog.adafruit.com>
40+
Adafruit Store <https://www.adafruit.com>
41+
42+
Indices and tables
43+
==================
44+
45+
* :ref:`genindex`
46+
* :ref:`modindex`
47+
* :ref:`search`

‎docs/index.rst.license

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
4+
SPDX-License-Identifier: MIT

‎docs/requirements.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
sphinx
6+
sphinxcontrib-jquery
7+
sphinx-rtd-theme

‎examples/pathlib_simpletest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
import adafruit_pathlib
5+
6+
7+
def print_directory_tree(path: adafruit_pathlib.Path, prefix: str = ""):
8+
"""Recursively prints an ASCII tree of the given directory."""
9+
if not path.is_dir():
10+
print(f"{path} is not a directory.")
11+
return
12+
13+
entries = sorted(path.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))
14+
for index, entry in enumerate(entries):
15+
connector = "├── " if index < len(entries) - 1 else "└── "
16+
print(f"{prefix}{connector}{entry.name}")
17+
if entry.is_dir():
18+
extension = "│ " if index < len(entries) - 1 else " "
19+
print_directory_tree(entry, prefix + extension)
20+
21+
22+
dir_path = adafruit_pathlib.Path("/lib")
23+
24+
print_directory_tree(dir_path)

‎optional_requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense

‎pyproject.toml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# SPDX-FileCopyrightText: 2022 Alec Delaney, written for Adafruit Industries
2+
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
#
4+
# SPDX-License-Identifier: MIT
5+
6+
[build-system]
7+
requires = [
8+
"setuptools",
9+
"wheel",
10+
"setuptools-scm",
11+
]
12+
13+
[project]
14+
name = "adafruit-circuitpython-pathlib"
15+
description = "Subset of the CPython module pathlib"
16+
version = "0.0.0+auto.0"
17+
readme = "README.rst"
18+
authors = [
19+
{name = "Adafruit Industries", email = "circuitpython@adafruit.com"}
20+
]
21+
urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_Pathlib"}
22+
keywords = [
23+
"adafruit",
24+
"blinka",
25+
"circuitpython",
26+
"micropython",
27+
"pathlib",
28+
"path",
29+
"pathlib",
30+
"file",
31+
"files",
32+
"dir",
33+
"folder",
34+
"directory",
35+
"filesystem",
36+
]
37+
license = {text = "MIT"}
38+
classifiers = [
39+
"Intended Audience :: Developers",
40+
"Topic :: Software Development :: Libraries",
41+
"Topic :: Software Development :: Embedded Systems",
42+
"Topic :: System :: Hardware",
43+
"License :: OSI Approved :: MIT License",
44+
"Programming Language :: Python :: 3",
45+
]
46+
dynamic = ["dependencies", "optional-dependencies"]
47+
48+
[tool.setuptools]
49+
# TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER,
50+
# CHANGE `py_modules = ['...']` TO `packages = ['...']`
51+
py-modules = ["adafruit_pathlib"]
52+
53+
[tool.setuptools.dynamic]
54+
dependencies = {file = ["requirements.txt"]}
55+
optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}

‎requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2+
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
3+
#
4+
# SPDX-License-Identifier: MIT
5+
6+
Adafruit-Blinka

‎ruff.toml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
target-version = "py38"
6+
line-length = 100
7+
8+
[lint]
9+
preview = true
10+
select = ["I", "PL", "UP"]
11+
12+
extend-select = [
13+
"D419", # empty-docstring
14+
"E501", # line-too-long
15+
"W291", # trailing-whitespace
16+
"PLC0414", # useless-import-alias
17+
"PLC2401", # non-ascii-name
18+
"PLC2801", # unnecessary-dunder-call
19+
"PLC3002", # unnecessary-direct-lambda-call
20+
"E999", # syntax-error
21+
"PLE0101", # return-in-init
22+
"F706", # return-outside-function
23+
"F704", # yield-outside-function
24+
"PLE0116", # continue-in-finally
25+
"PLE0117", # nonlocal-without-binding
26+
"PLE0241", # duplicate-bases
27+
"PLE0302", # unexpected-special-method-signature
28+
"PLE0604", # invalid-all-object
29+
"PLE0605", # invalid-all-format
30+
"PLE0643", # potential-index-error
31+
"PLE0704", # misplaced-bare-raise
32+
"PLE1141", # dict-iter-missing-items
33+
"PLE1142", # await-outside-async
34+
"PLE1205", # logging-too-many-args
35+
"PLE1206", # logging-too-few-args
36+
"PLE1307", # bad-string-format-type
37+
"PLE1310", # bad-str-strip-call
38+
"PLE1507", # invalid-envvar-value
39+
"PLE2502", # bidirectional-unicode
40+
"PLE2510", # invalid-character-backspace
41+
"PLE2512", # invalid-character-sub
42+
"PLE2513", # invalid-character-esc
43+
"PLE2514", # invalid-character-nul
44+
"PLE2515", # invalid-character-zero-width-space
45+
"PLR0124", # comparison-with-itself
46+
"PLR0202", # no-classmethod-decorator
47+
"PLR0203", # no-staticmethod-decorator
48+
"UP004", # useless-object-inheritance
49+
"PLR0206", # property-with-parameters
50+
"PLR0904", # too-many-public-methods
51+
"PLR0911", # too-many-return-statements
52+
"PLR0912", # too-many-branches
53+
"PLR0913", # too-many-arguments
54+
"PLR0914", # too-many-locals
55+
"PLR0915", # too-many-statements
56+
"PLR0916", # too-many-boolean-expressions
57+
"PLR1702", # too-many-nested-blocks
58+
"PLR1704", # redefined-argument-from-local
59+
"PLR1711", # useless-return
60+
"C416", # unnecessary-comprehension
61+
"PLR1733", # unnecessary-dict-index-lookup
62+
"PLR1736", # unnecessary-list-index-lookup
63+
64+
# ruff reports this rule is unstable
65+
#"PLR6301", # no-self-use
66+
67+
"PLW0108", # unnecessary-lambda
68+
"PLW0120", # useless-else-on-loop
69+
"PLW0127", # self-assigning-variable
70+
"PLW0129", # assert-on-string-literal
71+
"B033", # duplicate-value
72+
"PLW0131", # named-expr-without-context
73+
"PLW0245", # super-without-brackets
74+
"PLW0406", # import-self
75+
"PLW0602", # global-variable-not-assigned
76+
"PLW0603", # global-statement
77+
"PLW0604", # global-at-module-level
78+
79+
# fails on the try: import typing used by libraries
80+
#"F401", # unused-import
81+
82+
"F841", # unused-variable
83+
"E722", # bare-except
84+
"PLW0711", # binary-op-exception
85+
"PLW1501", # bad-open-mode
86+
"PLW1508", # invalid-envvar-default
87+
"PLW1509", # subprocess-popen-preexec-fn
88+
"PLW2101", # useless-with-lock
89+
"PLW3301", # nested-min-max
90+
]
91+
92+
ignore = [
93+
"PLR2004", # magic-value-comparison
94+
"UP030", # format literals
95+
"PLW1514", # unspecified-encoding
96+
"PLR0904", # Too many public methods
97+
98+
]
99+
100+
[format]
101+
line-ending = "lf"

0 commit comments

Comments
 (0)
Please sign in to comment.