Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add typechecking #51

Merged
merged 13 commits into from
Dec 4, 2018
9 changes: 5 additions & 4 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ twine = "*"
pytest-xdist = "*"
invoke = "*"
crayons = "*"
pythonfinder = {path = ".", editable = true}
pythonfinder = {path = ".",editable = true}
sphinx-rtd-theme = "*"
rope = "*"
black = {version = "*", markers = "python_version>='3.6'"}
black = {version = "*",markers = "python_version>='3.6'"}
parver = "*"
towncrier = "*"
mypy = {version = "*", markers = "python_version>='3.4'"}
mypy = {version = "*",markers = "python_version>='3.4'"}
mypy_extensions = "*"
typed-ast = {version = "*", markers = "python_version>='3.3'"}
typed-ast = {version = "*",markers = "python_version>='3.3'"}
jxltom marked this conversation as resolved.
Show resolved Hide resolved
lxml = "*"
sphinx-autodoc-types = "*"

[scripts]
black = "python -m black src/pythonfinder"
Expand Down
16 changes: 15 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 30 additions & 14 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ PythonFinder: Cross Platform Search Tool for Finding Pythons
=============================================================

.. image:: https://img.shields.io/pypi/v/pythonfinder.svg
:target: https://pypi.org/project/pythonfinder/
:target: https://pypi.org/project/pythonfinder

.. image:: https://img.shields.io/pypi/l/pythonfinder.svg
:target: https://pypi.org/project/pythonfinder/
:target: https://pypi.org/project/pythonfinder

.. image:: https://img.shields.io/pypi/pyversions/pythonfinder.svg
:target: https://pypi.org/project/pythonfinder/
:target: https://pypi.org/project/pythonfinder

.. image:: https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg
:target: https://saythanks.io/to/techalchemy
Expand All @@ -22,13 +22,13 @@ Installation

Install from `PyPI`_:

::
.. code-block:: console

$ pipenv install --pre pythonfinder
$ pipenv install pythonfinder

Install from `Github`_:

::
.. code-block:: console

$ pipenv install -e git+https://github.com/sarugaku/pythonfinder.git#egg=pythonfinder

Expand All @@ -44,19 +44,29 @@ Usage

Using PythonFinder is easy. Simply import it and ask for a python:

::
.. code-block:: pycon

>>> from pythonfinder.pythonfinder import PythonFinder
>>> PythonFinder.from_line('python3')
'/home/techalchemy/.pyenv/versions/3.6.5/python3'

>>> from pythonfinder import Finder
>>> f = Finder()
>>> f.find_python_version(3, minor=6)
PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.6.5/bin/python'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=3, minor=6, patch=5, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('3.6.5')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.6.5/bin/python'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)

>>> f.find_python_version(2)
PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=2, minor=7, patch=15, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('2.7.15')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), ...py_version=PythonVersion(major=2, minor=7, patch=15, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('2.7.15')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
>>> f.find_python_version("anaconda3-5.3.0")

Find a named distribution, such as ``anaconda3-5.3.0``:

.. code-block:: pycon

PythonFinder can even find beta releases!
PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/anaconda3-5.3.0/bin/python3.7m'), _children={'/home/hawk/.pyenv/versions/anaconda3-5.3.0/bin/python3.7m': ...}, only_python=False, name='anaconda3-5.3.0', _py_version=PythonVersion(major=3, minor=7, patch=0, is_prerelease=False, is_postrelease=False, is_devrelease=False,...))

::
PythonFinder can even find beta releases:

.. code-block:: pycon

>>> f.find_python_version(3, minor=7)
PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.7.0b1/bin/python'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=3, minor=7, patch=0, is_prerelease=True, is_postrelease=False, is_devrelease=False, version=<Version('3.7.0b1')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.7.0b1/bin/python'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
Expand All @@ -70,7 +80,7 @@ Windows Support

PythonFinder natively supports windows via both the *PATH* environment variable and `PEP-514 <https://www.python.org/dev/peps/pep-0514/>`_ compliant finder which comes by default with python 3. Usage on windows becomes:

::
.. code-block:: pycon

>>> from pythonfinder import Finder
>>> f = Finder()
Expand All @@ -88,7 +98,7 @@ Finding Executables

PythonFinder also provides **which** functionality across platforms, and it uses lazy loading and fast-returns to be performant at this task.

::
.. code-block:: pycon

>>> f.which('cmd')
PathEntry(path=WindowsPath('C:/windows/system32/cmd.exe'), _children={}, is_root=False, only_python=False, py_version=None, pythons=None)
Expand All @@ -106,13 +116,19 @@ PythonFinder also provides **which** functionality across platforms, and it uses
Architecture support
////////////////////

PythonFinder supports architecture specific lookups on all platforms (coming soon):
PythonFinder supports architecture specific lookups on all platforms:

.. code-block:: pycon

>>> f.find_python_version(3, minor=6, arch="64")
PathEntry(path=PosixPath('/usr/bin/python3'), _children={'/usr/bin/python3': ...}, only_python=False, name='python3', _py_version=PythonVersion(major=3, minor=6, patch=7, is_prerelease=False, is_postrelease=False, is_devrelease=False, is_debug=False, version=<Version('3.6.7')>, architecture='64bit', comes_from=..., executable='/usr/bin/python3', name='python3'), _pythons=defaultdict(None, {}), is_root=False)


Integrations
*************

* `Pyenv <https://github.com/pyenv/pyenv>`_
* `ASDF <https://github.com/asdf-vm/asdf>`_
* `PEP-514 <https://www.python.org/dev/peps/pep-0514/>`_
* `Virtualenv <https://github.com/pypa/virtualenv>`_
* `Pipenv <https://pipenv.org>`_
10 changes: 6 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def find_version(*file_paths):
project = 'PythonFinder'
copyright = '2018, Dan Ryan <dan@danryan.co>'
author = 'Dan Ryan <dan@danryan.co>'

autosummary_generate = True

# -- General configuration ---------------------------------------------------

Expand All @@ -72,7 +72,9 @@ def find_version(*file_paths):
'sphinx.ext.viewcode',
'sphinx.ext.todo',
'sphinx.ext.intersphinx',
'sphinx.ext.autosummary'
'sphinx.ext.autosummary',
'sphinx_autodoc_typehints',
'sphinx_click.ext'
]

# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -110,8 +112,8 @@ def find_version(*file_paths):
html_theme = "sphinx_rtd_theme"

extlinks = {
'issue': ('https://github.com/techalchemy/pythonfinder/issues/%s', '#'),
'pull': ('https://github.com/techalchemy/pythonfinder/pull/%s', 'PR #'),
'issue': ('https://github.com/sarugaku/pythonfinder/issues/%s', '#'),
'pull': ('https://github.com/sarugaku/pythonfinder/pull/%s', 'PR #'),
}
html_theme_options = {
'display_version': True,
Expand Down
2 changes: 1 addition & 1 deletion docs/pythonfinder.models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Submodules

.. toctree::

pythonfinder.models.mixins
pythonfinder.models.path
pythonfinder.models.pyenv
pythonfinder.models.python
pythonfinder.models.windows

2 changes: 1 addition & 1 deletion docs/pythonfinder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Submodules

pythonfinder.cli
pythonfinder.environment
pythonfinder.models
pythonfinder.exceptions
pythonfinder.pythonfinder
pythonfinder.utils

39 changes: 28 additions & 11 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ Installation

Install from `PyPI`_:

::
.. code-block:: console

$ pipenv install --pre pythonfinder
$ pipenv install pythonfinder

Install from `Github`_:

::
.. code-block:: console

$ pipenv install -e git+https://github.com/sarugaku/pythonfinder.git#egg=pythonfinder

Expand All @@ -44,7 +44,7 @@ Usage

Using PythonFinder is easy. Simply import it and ask for a python:

::
.. code-block:: pycon

>>> from pythonfinder.pythonfinder import PythonFinder
>>> PythonFinder.from_line('python3')
Expand All @@ -54,13 +54,19 @@ Using PythonFinder is easy. Simply import it and ask for a python:
>>> f = Finder()
>>> f.find_python_version(3, minor=6)
PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.6.5/bin/python'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=3, minor=6, patch=5, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('3.6.5')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.6.5/bin/python'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)

>>> f.find_python_version(2)
PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=2, minor=7, patch=15, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('2.7.15')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), ...py_version=PythonVersion(major=2, minor=7, patch=15, is_prerelease=False, is_postrelease=False, is_devrelease=False, version=<Version('2.7.15')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/shims/python2'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
>>> f.find_python_version("anaconda3-5.3.0")

Find a named distribution, such as ``anaconda3-5.3.0``:

.. code-block:: pycon

PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/anaconda3-5.3.0/bin/python3.7m'), _children={'/home/hawk/.pyenv/versions/anaconda3-5.3.0/bin/python3.7m': ...}, only_python=False, name='anaconda3-5.3.0', _py_version=PythonVersion(major=3, minor=7, patch=0, is_prerelease=False, is_postrelease=False, is_devrelease=False,...))

PythonFinder can even find beta releases!
PythonFinder can even find beta releases:

::
.. code-block:: pycon

>>> f.find_python_version(3, minor=7)
PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.7.0b1/bin/python'), _children={}, is_root=False, only_python=False, py_version=PythonVersion(major=3, minor=7, patch=0, is_prerelease=True, is_postrelease=False, is_devrelease=False, version=<Version('3.7.0b1')>, architecture='64bit', comes_from=PathEntry(path=PosixPath('/home/hawk/.pyenv/versions/3.7.0b1/bin/python'), _children={}, is_root=True, only_python=False, py_version=None, pythons=None), executable=None), pythons=None)
Expand All @@ -74,7 +80,7 @@ Windows Support

PythonFinder natively supports windows via both the *PATH* environment variable and `PEP-514 <https://www.python.org/dev/peps/pep-0514/>`_ compliant finder which comes by default with python 3. Usage on windows becomes:

::
.. code-block:: pycon

>>> from pythonfinder import Finder
>>> f = Finder()
Expand All @@ -92,7 +98,7 @@ Finding Executables

PythonFinder also provides **which** functionality across platforms, and it uses lazy loading and fast-returns to be performant at this task.

::
.. code-block:: pycon

>>> f.which('cmd')
PathEntry(path=WindowsPath('C:/windows/system32/cmd.exe'), _children={}, is_root=False, only_python=False, py_version=None, pythons=None)
Expand All @@ -110,13 +116,24 @@ PythonFinder also provides **which** functionality across platforms, and it uses
Architecture support
////////////////////

PythonFinder supports architecture specific lookups on all platforms (coming soon):
PythonFinder supports architecture specific lookups on all platforms:

.. code-block:: pycon

>>> f.find_python_version(3, minor=6, arch="64")
PathEntry(path=PosixPath('/usr/bin/python3'), _children={'/usr/bin/python3': ...}, only_python=False, name='python3', _py_version=PythonVersion(major=3, minor=6, patch=7, is_prerelease=False, is_postrelease=False, is_devrelease=False, is_debug=False, version=<Version('3.6.7')>, architecture='64bit', comes_from=..., executable='/usr/bin/python3', name='python3'), _pythons=defaultdict(None, {}), is_root=False)


Integrations
*************

* `Pyenv <https://github.com/pyenv/pyenv>`_
* `ASDF <https://github.com/asdf-vm/asdf>`_
* `PEP-514 <https://www.python.org/dev/peps/pep-0514/>`_
* `Virtualenv <https://github.com/pypa/virtualenv>`_
* `Pipenv <https://pipenv.org>`_


.. click:: pythonfinder:cli
:prog: pyfinder
:show-nested:
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
sphinx
sphinx-click
sphinx_rtd_theme
sphinx-autodoc-types
2 changes: 1 addition & 1 deletion src/pythonfinder/models/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ def as_dict(self):
}

def update_metadata(self, metadata):
# type: (Dict[Union[str, int, Version]]) -> None
# type: (Dict[str, Union[str, int, Version]]) -> None
"""
Update the metadata on the current :class:`pythonfinder.models.python.PythonVersion`

Expand Down
26 changes: 20 additions & 6 deletions src/pythonfinder/pythonfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class Finder(object):
"""
A cross-platform Finder for locating python and other executables.

Searches for python and other specified binaries starting in `path`, if supplied,
but searching the bin path of `sys.executable` if `system=True`, and then
searching in the `os.environ['PATH']` if `global_search=True`. When `global_search`
is `False`, this search operation is restricted to the allowed locations of
`path` and `system`.
Searches for python and other specified binaries starting in *path*, if supplied,
but searching the bin path of ``sys.executable`` if *system* is ``True``, and then
searching in the ``os.environ['PATH']`` if *global_search* is ``True``. When *global_search*
is ``False``, this search operation is restricted to the allowed locations of
*path* and *system*.
"""

def __init__(self, path=None, system=False, global_search=True, ignore_unsupported=True):
Expand All @@ -41,7 +41,7 @@ def __init__(self, path=None, system=False, global_search=True, ignore_unsupport

:param path: A bin-directory search location, defaults to None
:param path: str, optional
:param system: Whether to include the bin-dir of `sys.executable`, defaults to False
:param system: Whether to include the bin-dir of ``sys.executable``, defaults to False
:param system: bool, optional
:param global_search: Whether to search the global path from os.environ, defaults to True
:param global_search: bool, optional
Expand Down Expand Up @@ -122,6 +122,20 @@ def find_python_version(
self, major=None, minor=None, patch=None, pre=None, dev=None, arch=None, name=None
):
# type: (Optional[Union[str, int]], Optional[int], Optional[int], Optional[bool], Optional[bool], Optional[str], Optional[str]) -> PathEntry
"""
Find the python version which corresponds most closely to the version requested.

:param Union[str, int] major: The major version to look for, or the full version, or the name of the target version.
:param Optional[int] minor: The minor version. If provided, disables string-based lookups from the major version field.
:param Optional[int] patch: The patch version.
:param Optional[bool] pre: If provided, specifies whether to search pre-releases.
:param Optional[bool] dev: If provided, whether to search dev-releases.
:param Optional[str] arch: If provided, which architecture to search.
:param Optional[str] name: *Name* of the target python, e.g. ``anaconda3-5.3.0``
:return: A new *PathEntry* pointer at a matching python version, if one can be located.
:rtype: :class:`pythonfinder.models.path.PathEntry`
"""

from .models import PythonVersion
minor = int(minor) if minor is not None else minor
patch = int(patch) if patch is not None else patch
Expand Down