From 06b078a43e9cc9f13f75f3f04c863da8d125e547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Mon, 27 Sep 2021 09:27:19 +0100 Subject: [PATCH] Adopt tox-dev organization best practices (#87) --- .github/workflows/check.yml | 130 +++++++++++ .gitignore | 55 ++--- .pre-commit-config.yaml | 58 +++++ .travis.yml | 23 -- MANIFEST.in | 3 - README.md | 8 +- docs/Makefile | 177 --------------- docs/api.rst | 6 + docs/conf.py | 53 +++++ docs/index.rst | 14 ++ docs/license.rst | 6 + docs/make.bat | 242 --------------------- docs/source/conf.py | 272 ------------------------ docs/source/index.rst | 47 ---- example/example.py | 10 +- pyproject.toml | 18 ++ setup.cfg | 71 +++++++ setup.py | 70 +----- filelock.py => src/filelock/__init__.py | 57 +++-- test.py => tests/test_filelock.py | 32 ++- tox.ini | 125 +++++++++++ whitelist.txt | 44 ++++ 22 files changed, 587 insertions(+), 934 deletions(-) create mode 100644 .github/workflows/check.yml create mode 100644 .pre-commit-config.yaml delete mode 100644 .travis.yml delete mode 100644 MANIFEST.in delete mode 100644 docs/Makefile create mode 100644 docs/api.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/license.rst delete mode 100644 docs/make.bat delete mode 100644 docs/source/conf.py delete mode 100644 docs/source/index.rst create mode 100644 pyproject.toml create mode 100644 setup.cfg rename filelock.py => src/filelock/__init__.py (91%) rename test.py => tests/test_filelock.py (93%) create mode 100644 tox.ini create mode 100644 whitelist.txt diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..3472057 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,130 @@ +name: check +on: + push: + pull_request: + schedule: + - cron: "0 8 * * *" + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: pre-commit/action@v2.0.0 + + test: + name: test ${{ matrix.py }} - ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + py: + - 3.10.0-rc.2 + - 3.9 + - 3.8 + - 3.7 + - 3.6 + - 3.5 + - pypy3 + - 2.7 + - pypy2 + + steps: + - name: Setup python for tox + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install tox + run: python -m pip install tox + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup python for test ${{ matrix.py }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.py }} + - name: Pick environment to run + run: | + import platform; import os; import sys; import codecs + cpy = platform.python_implementation() == "CPython" + base =("{}{}{}" if cpy else "{}{}").format("py" if cpy else "pypy", *sys.version_info[0:2]) + env = "TOXENV={}\n".format(base) + print("Picked:\n{}for{}".format(env, sys.version)) + with codecs.open(os.environ["GITHUB_ENV"], "a", "utf-8") as file_handler: + file_handler.write(env) + shell: python + - name: Setup test suite + run: tox -vv --notest + - name: Run test suite + run: tox --skip-pkg-install + env: + PYTEST_ADDOPTS: "-vv --durations=20" + CI_RUN: "yes" + DIFF_AGAINST: HEAD + - name: Rename coverage report file + run: | + import os; os.rename('.tox/coverage.{}.xml'.format(os.environ['TOXENV']), '.tox/coverage.xml') + shell: python + - uses: codecov/codecov-action@v1 + with: + file: ./.tox/coverage.xml + flags: tests + name: ${{ matrix.py }} - ${{ matrix.os }} + + check: + name: ${{ matrix.tox_env }} - ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + tox_env: + - dev + - docs + - readme + exclude: + - { os: windows-latest, tox_env: readme } + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install tox + run: python -m pip install tox + - name: Setup test suite + run: tox -vv --notest -e ${{ matrix.tox_env }} + - name: Run test suite + run: tox --skip-pkg-install -e ${{ matrix.tox_env }} + + publish: + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: [check, test, lint] + runs-on: ubuntu-latest + steps: + - name: Setup python to build package + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install https://pypi.org/project/build + run: python -m pip install build + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Build sdist and wheel + run: python -m build -s -w . -o dist + - name: Publish to PyPi + uses: pypa/gh-action-pypi-publish@master + with: + skip_existing: true + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/.gitignore b/.gitignore index 727de6e..74590d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,45 +1,18 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg *.egg-info -dist build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 -*__pycache__ -MANIFEST - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage +dist +*.egg +.eggs +*.py[codz] +*$py.class .tox -nosetests.xml - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# py-filelock -# ----------- - -# Docs -docs/build - +.*_cache +.DS_Store +.idea +.vscode +/pip-wheel-metadata +/src/filelock/version.py +venv* +.python-version test.lock +test.softlock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c7477bf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,58 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-ast + - id: check-builtin-literals + - id: check-docstring-first + - id: check-merge-conflict + - id: check-yaml + - id: check-toml + - id: debug-statements + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/asottile/pyupgrade + rev: v2.26.0 + hooks: + - id: pyupgrade + - repo: https://github.com/PyCQA/isort + rev: 5.9.3 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 21.9b0 + hooks: + - id: black + args: [ --safe ] + - repo: https://github.com/asottile/blacken-docs + rev: v1.11.0 + hooks: + - id: blacken-docs + additional_dependencies: [ black==20.8b1 ] + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: rst-backticks + - repo: https://github.com/tox-dev/tox-ini-fmt + rev: "0.5.1" + hooks: + - id: tox-ini-fmt + args: [ "-p", "fix_lint" ] + - repo: https://github.com/asottile/setup-cfg-fmt + rev: v1.17.0 + hooks: + - id: setup-cfg-fmt + args: [ --min-py3-version, "3.5", "--max-py-version", "3.10" ] + - repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear==21.9.1 + - flake8-comprehensions==3.6.1 + - flake8-pytest-style==1.5 + - flake8-spellcheck==0.24 + - flake8-unused-arguments==0.0.6 + - flake8-noqa==1.1.0 + - flake8-eradicate==1.1.0 + - pep8-naming==0.12.1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7ee4663..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: python - -cache: pip - -matrix: - fast_finish: true - include: - - python: "2.7" - - python: "3.4" - - python: "3.5" - - python: "3.6" - - python: "3.7" - dist: xenial - - python: "3.8-dev" - dist: xenial - allow_failures: - - python: "3.8-dev" - -install: - - pip install -e . - -script: - - pytest -xvv test.py diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 9adac78..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include README.md -include test.py -include LICENSE diff --git a/README.md b/README.md index a515688..ab21202 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ # py-filelock -![travis-ci](https://travis-ci.org/benediktschmitt/py-filelock.svg?branch=master) - This package contains a single module, which implements a platform independent file lock in Python, which provides a simple way of inter-process communication: ```Python -from filelock import Timeout, FileLock +from src.filelock import Timeout, FileLock lock = FileLock("high_ground.txt.lock") with lock: - open("high_ground.txt", "a").write("You were the chosen one.") + open("high_ground.txt", "a").write("You were the chosen one.") ``` **Don't use** a *FileLock* to lock the file you want to write to, instead create @@ -50,7 +48,7 @@ resource or working directory is currently used. To do so, create a *FileLock* first: ```Python -from filelock import Timeout, FileLock +from src.filelock import Timeout, FileLock file_path = "high_ground.txt" lock_path = "high_ground.txt.lock" diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4b1445..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/py-filelock.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/py-filelock.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/py-filelock" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/py-filelock" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..17347d9 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,6 @@ +API +=== + +.. automodule:: filelock + :members: + :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..c821841 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +from datetime import date, datetime + +from filelock import __version__ + +company = "tox-dev" +name = "py-filelock" +version = ".".join(__version__.split(".")[:2]) +release = __version__ +copyright = f"2014-{date.today().year}, {company}" + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + "sphinx_autodoc_typehints", +] + +templates_path = [] +unused_docs = [] +source_suffix = ".rst" +exclude_patterns = ["_build"] + +master_doc = "index" +pygments_style = "default" + +project = name +today_fmt = "%B %d, %Y" + +html_theme = "furo" +html_theme_options = { + "navigation_with_keys": True, +} +html_title = "py-filelock" +html_last_updated_fmt = datetime.now().isoformat() + +autoclass_content = "class" +autodoc_member_order = "bysource" +autodoc_default_options = { + "member-order": "bysource", + "undoc-members": True, + "show-inheritance": True, +} +autodoc_typehints = "none" +always_document_param_types = False +typehints_fully_qualified = True +autosectionlabel_prefix_document = True + +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} +nitpicky = True +nitpick_ignore = [] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..8bdf2fa --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,14 @@ +py-filelock +=========== + +.. toctree:: + + api + license + +GitHub +------ + +This module is hosted on +`GitHub `_. If you have any +questions or suggestions, don't hesitate to open a new issue :). diff --git a/docs/license.rst b/docs/license.rst new file mode 100644 index 0000000..1c3769a --- /dev/null +++ b/docs/license.rst @@ -0,0 +1,6 @@ +License +======= + +*py-filelock* is public domain: + +.. literalinclude:: ../LICENSE diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 316d0a8..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\py-filelock.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\py-filelock.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index ede32b9..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,272 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# py-filelock documentation build configuration file, created by -# sphinx-quickstart on Mon May 25 02:40:04 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import alabaster - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../../')) - -# py-filelock -import filelock - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'py-filelock' -copyright = '2015, Benedikt Schmitt' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = filelock.__version__ -# The full version, including alpha/beta/rc tags. -release = filelock.__version__ - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = [alabaster.get_path()] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'py-filelockdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'py-filelock.tex', 'py-filelock Documentation', - 'Benedikt Schmitt', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'py-filelock', 'py-filelock Documentation', - ['Benedikt Schmitt'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'py-filelock', 'py-filelock Documentation', - 'Benedikt Schmitt', 'py-filelock', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index 1c7f662..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,47 +0,0 @@ -py-filelock -=========== - -.. automodule:: filelock - :members: - :show-inheritance: - - -License -------- - -*py-filelock* is public domain: - -.. code-block:: none - - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to - - -GitHub ------- - -This module is hosted on -`GitHub `_. If you have any -questions or suggestions, don't hesitate to open a new issue :). diff --git a/example/example.py b/example/example.py index 924aee6..da1e258 100644 --- a/example/example.py +++ b/example/example.py @@ -2,11 +2,11 @@ import sys from time import sleep -from filelock import FileLock + +from src.filelock import FileLock lock = FileLock("my_lock") with lock: - print("This is process {}.".format(sys.argv[1])) - sleep(1) - print("Bye.") - + print("This is process {}.".format(sys.argv[1])) + sleep(1) + print("Bye.") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a7c5cb3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = [ + "setuptools >= 41.0.0", + "wheel >= 0.30.0", + "setuptools_scm >= 2", +] +build-backend = 'setuptools.build_meta' + +[tool.black] +line-length = 120 + +[tool.isort] +line_length = 120 +profile = "black" +known_first_party = ["filelock", "tests"] + +[tool.setuptools_scm] +write_to = "src/filelock/version.py" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..719383e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,71 @@ +[metadata] +name = filelock +description = A platform independent file lock. +long_description = file: README.md +long_description_content_type = text/markdown +url = https://github.com/tox-dev/py-filelock +author = Benedikt Schmitt +author_email = benedikt@benediktschmitt.de +license = Unlicense +license_file = LICENSE +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Developers + License :: Public Domain + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Topic :: Internet + Topic :: Software Development :: Libraries + Topic :: System +download_url = https://github.com/benediktschmitt/tox-dev/archive/main.zip +project_urls = + Source=https://github.com/pypa/virtualenv + Tracker=https://github.com/pypa/virtualenv/issues + +[options] +packages = find: +python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +package_dir = + =src +zip_safe = True + +[options.packages.find] +where = src + +[options.extras_require] +docs = + furo>=2021.8.17b43 + sphinx>=4.1 + sphinx-autodoc-typehints>=1.12 +testing = + coverage>=4 + pytest>=4 + pytest-cov + +[bdist_wheel] +universal = true + +[coverage:report] +show_missing = True + +[coverage:paths] +source = + src + .tox/*/lib/python*/site-packages + .tox/pypy*/site-packages + .tox\*\Lib\site-packages\ + */src + *\src + +[coverage:run] +branch = true +parallel = true diff --git a/setup.py b/setup.py index 26cbd57..6068493 100644 --- a/setup.py +++ b/setup.py @@ -1,71 +1,3 @@ -#!/usr/bin/env python - -# This is free and unencumbered software released into the public domain. -# -# Anyone is free to copy, modify, publish, use, compile, sell, or -# distribute this software, either in source code form or as a compiled -# binary, for any purpose, commercial or non-commercial, and by any -# means. -# -# In jurisdictions that recognize copyright laws, the author or authors -# of this software dedicate any and all copyright interest in the -# software to the public domain. We make this dedication for the benefit -# of the public at large and to the detriment of our heirs and -# successors. We intend this dedication to be an overt act of -# relinquishment in perpetuity of all present and future rights to this -# software under copyright law. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# For more information, please refer to - - -# Modules -# ------------------------------------------------ from setuptools import setup -from filelock import __version__ - -# Main -# ------------------------------------------------ -try: - long_description = open("README.md").read() -except (OSError, IOError): - long_description = "not available" -setup( - name = "filelock", - version = __version__, - description = "A platform independent file lock.", - long_description = long_description, - long_description_content_type = "text/markdown", - author = "Benedikt Schmitt", - author_email = "benedikt@benediktschmitt.de", - url = "https://github.com/benediktschmitt/py-filelock", - download_url = "https://github.com/benediktschmitt/py-filelock/archive/master.zip", - py_modules = ["filelock"], - license = "Public Domain ", - test_suite="test", - classifiers = [ - "License :: Public Domain", - "Development Status :: 5 - Production/Stable", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Intended Audience :: Developers", - "Topic :: System", - "Topic :: Internet", - "Topic :: Software Development :: Libraries" - ], - ) +setup() diff --git a/filelock.py b/src/filelock/__init__.py similarity index 91% rename from filelock.py rename to src/filelock/__init__.py index 4c98167..63e5b24 100644 --- a/filelock.py +++ b/src/filelock/__init__.py @@ -26,14 +26,15 @@ """ A platform independent file lock that supports the with-statement. """ - - # Modules # ------------------------------------------------ import logging import os import threading import time + +from .version import version as __version__ + try: import warnings except ImportError: @@ -60,19 +61,10 @@ # Data # ------------------------------------------------ -__all__ = [ - "Timeout", - "BaseFileLock", - "WindowsFileLock", - "UnixFileLock", - "SoftFileLock", - "FileLock" -] - -__version__ = "3.0.12" +__all__ = ["Timeout", "BaseFileLock", "WindowsFileLock", "UnixFileLock", "SoftFileLock", "FileLock", "__version__"] +_logger = None -_logger = None def logger(): """Returns the logger instance used in this module.""" global _logger @@ -89,15 +81,13 @@ class Timeout(TimeoutError): """ def __init__(self, lock_file): - """ - """ + """ """ #: The path of the file lock. self.lock_file = lock_file return None def __str__(self): - temp = "The file lock '{}' could not be acquired."\ - .format(self.lock_file) + temp = "The file lock '{}' could not be acquired.".format(self.lock_file) return temp @@ -113,7 +103,6 @@ def __str__(self): # # :seealso: issue #37 (memory leak) class _Acquire_ReturnProxy(object): - def __init__(self, lock): self.lock = lock return None @@ -131,9 +120,8 @@ class BaseFileLock(object): Implements the base class of a file lock. """ - def __init__(self, lock_file, timeout = -1): - """ - """ + def __init__(self, lock_file, timeout=-1): + """ """ # The path to the lock file. self._lock_file = lock_file @@ -180,8 +168,7 @@ def timeout(self): @timeout.setter def timeout(self, value): - """ - """ + """ """ self._timeout = float(value) return None @@ -267,19 +254,18 @@ def acquire(self, timeout=None, poll_intervall=0.05): while True: with self._thread_lock: if not self.is_locked: - logger().debug('Attempting to acquire lock %s on %s', lock_id, lock_filename) + logger().debug("Attempting to acquire lock %s on %s", lock_id, lock_filename) self._acquire() if self.is_locked: - logger().info('Lock %s acquired on %s', lock_id, lock_filename) + logger().info("Lock %s acquired on %s", lock_id, lock_filename) break elif timeout >= 0 and time.time() - start_time > timeout: - logger().debug('Timeout on acquiring lock %s on %s', lock_id, lock_filename) + logger().debug("Timeout on acquiring lock %s on %s", lock_id, lock_filename) raise Timeout(self._lock_file) else: logger().debug( - 'Lock %s not acquired on %s, waiting %s seconds ...', - lock_id, lock_filename, poll_intervall + "Lock %s not acquired on %s, waiting %s seconds ...", lock_id, lock_filename, poll_intervall ) time.sleep(poll_intervall) except: @@ -288,9 +274,9 @@ def acquire(self, timeout=None, poll_intervall=0.05): self._lock_counter = max(0, self._lock_counter - 1) raise - return _Acquire_ReturnProxy(lock = self) + return _Acquire_ReturnProxy(lock=self) - def release(self, force = False): + def release(self, force=False): """ Releases the file lock. @@ -312,10 +298,10 @@ def release(self, force = False): lock_id = id(self) lock_filename = self._lock_file - logger().debug('Attempting to release lock %s on %s', lock_id, lock_filename) + logger().debug("Attempting to release lock %s on %s", lock_id, lock_filename) self._release() self._lock_counter = 0 - logger().info('Lock %s released on %s', lock_id, lock_filename) + logger().info("Lock %s released on %s", lock_id, lock_filename) return None @@ -328,13 +314,14 @@ def __exit__(self, exc_type, exc_value, traceback): return None def __del__(self): - self.release(force = True) + self.release(force=True) return None # Windows locking mechanism # ~~~~~~~~~~~~~~~~~~~~~~~~~ + class WindowsFileLock(BaseFileLock): """ Uses the :func:`msvcrt.locking` function to hard lock the lock file on @@ -371,9 +358,11 @@ def _release(self): pass return None + # Unix locking mechanism # ~~~~~~~~~~~~~~~~~~~~~~ + class UnixFileLock(BaseFileLock): """ Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems. @@ -402,9 +391,11 @@ def _release(self): os.close(fd) return None + # Soft lock # ~~~~~~~~~ + class SoftFileLock(BaseFileLock): """ Simply watches the existence of the lock file. diff --git a/test.py b/tests/test_filelock.py similarity index 93% rename from test.py rename to tests/test_filelock.py index 7714961..41fd29b 100644 --- a/test.py +++ b/tests/test_filelock.py @@ -30,21 +30,19 @@ Some tests for the file lock. """ +import errno import os import sys -import unittest import threading -import errno +import unittest import filelock - PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 class ExThread(threading.Thread): - def __init__(self, *args, **kargs): threading.Thread.__init__(self, *args, **kargs) self.ex = None @@ -173,7 +171,7 @@ def test_nested_forced_release(self): lock.acquire() self.assertTrue(lock.is_locked) - lock.release(force = True) + lock.release(force=True) self.assertFalse(lock.is_locked) self.assertFalse(lock.is_locked) return None @@ -194,7 +192,7 @@ def my_thread(): NUM_THREADS = 250 - threads = [ExThread(target = my_thread) for i in range(NUM_THREADS)] + threads = [ExThread(target=my_thread) for i in range(NUM_THREADS)] for thread in threads: thread.start() for thread in threads: @@ -209,6 +207,7 @@ def test_threaded1(self): FileLock object. When thread group 1 acquired the lock, thread group 2 must not hold their lock. """ + def thread1(): """ Requires lock1. @@ -216,7 +215,7 @@ def thread1(): for i in range(1000): with lock1: self.assertTrue(lock1.is_locked) - self.assertFalse(lock2.is_locked) # FIXME (Filelock) + self.assertFalse(lock2.is_locked) # FIXME (Filelock) return None def thread2(): @@ -225,17 +224,17 @@ def thread2(): """ for i in range(1000): with lock2: - self.assertFalse(lock1.is_locked) # FIXME (FileLock) + self.assertFalse(lock1.is_locked) # FIXME (FileLock) self.assertTrue(lock2.is_locked) return None - NUM_THREADS = 10 + NUM_THREADS = 10 lock1 = self.LOCK_TYPE(self.LOCK_PATH) lock2 = self.LOCK_TYPE(self.LOCK_PATH) - threads1 = [ExThread(target = thread1) for i in range(NUM_THREADS)] - threads2 = [ExThread(target = thread2) for i in range(NUM_THREADS)] + threads1 = [ExThread(target=thread1) for i in range(NUM_THREADS)] + threads2 = [ExThread(target=thread2) for i in range(NUM_THREADS)] for i in range(NUM_THREADS): threads1[i].start() @@ -261,7 +260,7 @@ def test_timeout(self): self.assertFalse(lock2.is_locked) # Try to acquire lock 2. - self.assertRaises(filelock.Timeout, lock2.acquire, timeout=1) # FIXME (Filelock) + self.assertRaises(filelock.Timeout, lock2.acquire, timeout=1) # FIXME (Filelock) self.assertFalse(lock2.is_locked) self.assertTrue(lock1.is_locked) @@ -276,7 +275,7 @@ def test_default_timeout(self): Test if the default timeout parameter works. """ lock1 = self.LOCK_TYPE(self.LOCK_PATH) - lock2 = self.LOCK_TYPE(self.LOCK_PATH, timeout = 1) + lock2 = self.LOCK_TYPE(self.LOCK_PATH, timeout=1) self.assertEqual(lock2.timeout, 1) @@ -286,7 +285,7 @@ def test_default_timeout(self): self.assertFalse(lock2.is_locked) # Try to acquire lock 2. - self.assertRaises(filelock.Timeout, lock2.acquire) # FIXME (SoftFileLock) + self.assertRaises(filelock.Timeout, lock2.acquire) # FIXME (SoftFileLock) self.assertFalse(lock2.is_locked) self.assertTrue(lock1.is_locked) @@ -334,8 +333,7 @@ def test_context1(self): self.assertFalse(lock.is_locked) return None - @unittest.skipIf(hasattr(sys, 'pypy_version_info'), - 'del() does not trigger GC in PyPy') + @unittest.skipIf(hasattr(sys, "pypy_version_info"), "del() does not trigger GC in PyPy") def test_del(self): """ Tests, if the lock is released, when the object is deleted. @@ -349,7 +347,7 @@ def test_del(self): self.assertFalse(lock2.is_locked) # Try to acquire lock 2. - self.assertRaises(filelock.Timeout, lock2.acquire, timeout = 1) # FIXME (SoftFileLock) + self.assertRaises(filelock.Timeout, lock2.acquire, timeout=1) # FIXME (SoftFileLock) # Delete lock 1 and try to acquire lock 2 again. del lock1 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..23c748f --- /dev/null +++ b/tox.ini @@ -0,0 +1,125 @@ +[tox] +envlist = + fix_lint + py310 + py39 + py38 + py37 + py36 + py35 + py27 + pypy3 + pypy2 + coverage + docs + readme +isolated_build = true +skip_missing_interpreters = true +minversion = 3.14 + +[testenv] +description = run tests with {basepython} +passenv = + PIP_* + PYTEST_* +setenv = + COVERAGE_FILE = {toxworkdir}/.coverage.{envname} + {py27,pypy2}: PYTHONWARNINGS = ignore:DEPRECATION::pip._internal.cli.base_command +extras = + testing +commands = + pytest {tty:--color=yes} {posargs: \ + --junitxml {toxworkdir}{/}junit.{envname}.xml --cov filelock --cov {toxinidir}{/}tests \ + --cov-config=setup.cfg --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \ + --cov-fail-under 80 --cov-report html:{envtmpdir}{/}htmlcov \ + --cov-report xml:{toxworkdir}{/}coverage.{envname}.xml \ + tests} +package = wheel +wheel_build_env = .pkg + +[testenv:fix_lint] +description = format the code base to adhere to our styles, and complain about what we cannot do automatically +passenv = + * +basepython = python3.9 +skip_install = true +deps = + pre-commit>=2 +commands = + pre-commit run --all-files --show-diff-on-failure + python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))' + +[testenv:coverage] +description = [run locally after tests]: combine coverage data and create report; + generates a diff coverage against origin/main (can be changed by setting DIFF_AGAINST env var) +passenv = + DIFF_AGAINST +setenv = + COVERAGE_FILE = {toxworkdir}/.coverage +skip_install = true +deps = + coverage>=5.0.1 + diff_cover>=3 +extras = +parallel_show_output = true +commands = + python -m coverage combine + python -m coverage report --skip-covered --show-missing + python -m coverage xml -o {toxworkdir}/coverage.xml + python -m coverage html -d {toxworkdir}/htmlcov + python -m diff_cover.diff_cover_tool --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}/coverage.xml +depends = + py39 + py38 + py37 + py36 + py35 + py27 + pypy + pypy3 + +[testenv:docs] +description = build documentation +extras = + docs +commands = + sphinx-build -d "{envtmpdir}{/}doctree" docs "{toxworkdir}{/}docs_out" --color -b html {posargs} + python -c 'print(r"documentation available under file://{toxworkdir}{/}docs_out{/}index.html")' + +[testenv:readme] +description = check that the long description is valid (need for PyPI) +skip_install = true +deps = + build>=0.6 + twine>=3 +extras = +commands = + python -m build -o {envtmpdir} --wheel --sdist . + twine check {envtmpdir}/* + +[testenv:dev] +description = generate a DEV environment +usedevelop = true +extras = + docs + testing +commands = + python -m pip list --format=columns + python -c 'import sys; print(sys.executable)' + +[flake8] +max-complexity = 22 +max-line-length = 120 +ignore = + N801 # CapWord convention + N806 # variable should be in lowercase + U100 # unused arguments + PT009 # use regular assert + E722 # bare except + B001 # bare except + B007 # loop variable not used within body + B014 # redundant exception + E741 # ambiguous variable + +[pep8] +max-line-length = 120 diff --git a/whitelist.txt b/whitelist.txt new file mode 100644 index 0000000..fac0e8e --- /dev/null +++ b/whitelist.txt @@ -0,0 +1,44 @@ +autoclass +autodoc +autosectionlabel +context1 +creat +enoent +exc +fcntl +filelock +fmt +intersphinx +intervall +kargs +l1 +l2 +l3 +lk +lock1 +lock2 +lockfile +merchantability +msvcrt +nblck +nested1 +nitpicky +noninfringement +num +param +pygments +rdwr +returnproxy +seealso +src +thread1 +thread2 +threaded1 +threads1 +threads2 +trunc +typehints +unittest +unlck +unlicense +wronly