diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dfe3d8cb14166602f59afe8ac6ab5bac4b429cf..e0a85801c822ce3894bd7cef871e45200b43f2bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # v2.25.0 +* added safe_listdir +* fixed a bug occurring in Python 3.10 with whereis + Build system ============ diff --git a/README.md b/README.md index 49b81e781b889b3494fe60bcc04cba72efed5b41..26998ea627d1263c512f0eebc1a0b23604e0865a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ satella ======== -[](https://codeclimate.com/github/piotrmaslanka/satella/test_coverage) +[](https://codeclimate.com/github/piotrmaslanka/satella/test_coverage) [](https://codeclimate.com/github/piotrmaslanka/satella) [](https://codeclimate.com/github/piotrmaslanka/satella) [](https://pypi.python.org/pypi/satella) diff --git a/docs/files.rst b/docs/files.rst index 4a395c48bdfdbe46c15d341cebe8032011d63dde..7f2b1b01b59dc72cd52a9a21f03a9e1f7c26f7ab 100644 --- a/docs/files.rst +++ b/docs/files.rst @@ -9,6 +9,11 @@ A file-like object that will dispose of your content. .. autoclass:: satella.files.DevNullFilelikeObject :members: +safe_listdir +------------ + +.. autofunction:: satella.os.safe_listdir + read_lines ---------- diff --git a/pyproject.toml b/pyproject.toml index 7d1bbf9bcc8d2334ccf6b2fe64ac46b8d702283c..429d63c8de8367bfe5f60bd1fae7c9f4bb9cc40d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,37 +2,37 @@ name = "satella" dynamic = ["version"] description = "Utilities for writing servers in Python" -readme = {file = "README.md", content-type="text/markdown"} +readme = { file = "README.md", content-type = "text/markdown" } authors = [ - {name = "Piotr MaĹlanka", email = "pmaslanka@smok.co"} + { name = "Piotr MaĹlanka", email = "pmaslanka@smok.co" } ] requires-python = ">= 3.7" -license = {text="MIT License"} +license = { text = "MIT License" } keywords = ["ha", "high availability", "scalable", "scalability", "server", "metrics", "tracing", "instrumentation"] classifiers = [ - "Programming Language :: Python", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Operating System :: OS Independent", - "Development Status :: 5 - Production/Stable", - "License :: OSI Approved :: MIT License", - "Topic :: Software Development :: Libraries" + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Libraries" ] dependencies = ["psutil"] [tool.setuptools.dynamic] -version = {attr = "satella.__version__"} +version = { attr = "satella.__version__" } [project.optional-dependencies] dev = ["pylint", "toml", "requests", "codeclimate-test-reporter", "opentracing"] -test = ["pytest-cov", "pytest-xdist", "pytest", "pytest-forked", "pluggy", "py", "coverage"] -extras = ["requests","pyyaml","toml", "ujson", "cassandra-driver", "opentracing"] +test = ["pytest-cov", "pytest-xdist", "pytest", "pytest-forked", "pluggy", "py", "coverage"] +extras = ["requests", "pyyaml", "toml", "ujson", "cassandra-driver", "opentracing"] [build-system] @@ -54,35 +54,35 @@ Changelog = "https://github.com/piotrmaslanka/satella/blob/develop/CHANGELOG.md" [tool.setuptools] packages = ["satella", - "satella.cassandra", - "satella.coding", - "satella.coding.concurrent", - "satella.coding.concurrent.futures", - "satella.coding.decorators", - "satella.coding.resources", - "satella.coding.sequences", - "satella.coding.structures", - "satella.coding.structures.dictionaries", - "satella.coding.structures.heaps", - "satella.coding.structures.mixins", - "satella.coding.transforms", - "satella.configuration", - "satella.configuration.schema", - "satella.configuration.sources", - "satella.debug", - "satella.debug.tainting", - "satella.exception_handling", - "satella.instrumentation", - "satella.instrumentation.cpu_time", - "satella.instrumentation.memory", - "satella.instrumentation.metrics", - "satella.instrumentation.metrics.exporters", - "satella.instrumentation.metrics.metric_types", - "satella.instrumentation.metrics.structures", - "satella.instrumentation.trace_back", - "satella.opentracing", - "satella.os", - "satella.time"] + "satella.cassandra", + "satella.coding", + "satella.coding.concurrent", + "satella.coding.concurrent.futures", + "satella.coding.decorators", + "satella.coding.resources", + "satella.coding.sequences", + "satella.coding.structures", + "satella.coding.structures.dictionaries", + "satella.coding.structures.heaps", + "satella.coding.structures.mixins", + "satella.coding.transforms", + "satella.configuration", + "satella.configuration.schema", + "satella.configuration.sources", + "satella.debug", + "satella.debug.tainting", + "satella.exception_handling", + "satella.instrumentation", + "satella.instrumentation.cpu_time", + "satella.instrumentation.memory", + "satella.instrumentation.metrics", + "satella.instrumentation.metrics.exporters", + "satella.instrumentation.metrics.metric_types", + "satella.instrumentation.metrics.structures", + "satella.instrumentation.trace_back", + "satella.opentracing", + "satella.os", + "satella.time"] [tool.pytest] log_cli = true @@ -104,16 +104,16 @@ disable = ''' branch = true source = ["satella"] concurrency = ["thread"] -omit= [ - "tests/*", - ".eggs/*", - "setup.py", - "satella/__init__.py", - "satella/os/signals.py" +omit = [ + "tests/*", + ".eggs/*", + "setup.py", + "satella/__init__.py", + "satella/os/signals.py" ] [tool.coverage.report] -include=[ +include = [ "satella/*" ] diff --git a/satella/__init__.py b/satella/__init__.py index e92ec042c940c33109897171e454a2e27428bc80..507e1b6be362c54a8b3c4fbff9902325a760c53a 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.25.0a1' +__version__ = '2.25.0a2' diff --git a/satella/os/__init__.py b/satella/os/__init__.py index e06e8f70503d727b846fa44b9326cb5b94d11f16..f42cd9ad00e4a682279c2622d5e826a4a5b72199 100644 --- a/satella/os/__init__.py +++ b/satella/os/__init__.py @@ -1,10 +1,10 @@ from satella.os.daemon import daemonize -from satella.os.misc import suicide, is_running_as_root, whereis +from satella.os.misc import suicide, is_running_as_root, whereis, safe_listdir from satella.os.pidlock import PIDFileLock from satella.os.signals import hang_until_sig __all__ = [ - 'daemonize', 'whereis', + 'daemonize', 'whereis', 'safe_listdir', 'PIDFileLock', 'hang_until_sig', 'suicide', 'is_running_as_root' ] diff --git a/satella/os/misc.py b/satella/os/misc.py index 60663870309da9f7c00cc0732fa70fbf45e62e33..d01fcd4abb3823bf87df775ae8c79df986ffe3df 100644 --- a/satella/os/misc.py +++ b/satella/os/misc.py @@ -30,9 +30,23 @@ def whereis(name: str) -> tp.Iterator[str]: yield from _whereis(directory, name, available_extensions) +def safe_listdir(directory: str) -> tp.Iterator[str]: + """ + Return elements of directory. + + Retuns nothing if directory does not exist, or is not a directory. + + :param directory: path to the element. + """ + try: + yield from os.listdir(directory) + except (FileNotFoundError, NotADirectoryError): + return + + @silence_excs(FileNotFoundError) def _whereis(directory: str, name, available_extensions): - for file in os.listdir(directory): + for file in safe_listdir(directory): path = os.path.join(directory, file) if 'x' in stat.filemode(os.stat(path).st_mode): if sys.platform.startswith('win'): # a POSIX-specific check diff --git a/tests/test_os/test_whereis.py b/tests/test_os/test_whereis.py index 27862b0c913736ac274edac732e910a92b95b4bf..08692b797220c1df0d75d5baf747c0616d6620a0 100644 --- a/tests/test_os/test_whereis.py +++ b/tests/test_os/test_whereis.py @@ -1,6 +1,7 @@ +import os import unittest -from satella.os import whereis +from satella.os import whereis, safe_listdir class TestWhereis(unittest.TestCase): @@ -8,5 +9,9 @@ class TestWhereis(unittest.TestCase): """ Note that it will fail on Windows unless you have PYTHON.EXE in your path """ + self.assertEqual(list(safe_listdir('test22')), []) execs = list(whereis('python')) + self.assertTrue(os.path.exists(execs[1])) self.assertGreaterEqual(len(execs), 1) + +