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

Add support for Pipfiles #31

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![GitHub contributors](https://img.shields.io/github/contributors/nasirhjafri/libyear.svg)](https://GitHub.com/nasirhjafri/libyear/graphs/contributors/)


# libyear
# libyear

A **simple** measure of software dependency freshness. It is a **single number** telling you how up-to-date your dependencies are.

Expand All @@ -23,9 +23,12 @@ A single requirement file
A folder with requirement files
`libyear -r requirements/`

A Pipfile
`libyear -p Pipfile`

## Example output
```
libyear -r requirements.txt
libyear -r requirements.txt
+-------------------------+-----------------+----------------+-----------------+
| Library | Current Version | Latest Version | Libyears behind |
+-------------------------+-----------------+----------------+-----------------+
Expand Down
21 changes: 15 additions & 6 deletions libyear/libyear
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,39 @@ import argparse
from prettytable import PrettyTable

from libyear.pypi import get_lib_days, get_no_of_releases
from libyear.utils import load_requirements, get_requirement_files, get_requirement_name_and_version
from libyear.utils import load_requirements, get_requirement_files, load_pipfile, get_requirement_name_and_version


def main():
parser = argparse.ArgumentParser()
parser.add_argument('-r', help="Requirements file/path", action='store')
parser.add_argument('-p', help="Pipfile path", action='store')
parser.add_argument('--sort', help="Sort by years behind, in descending order", action='store_true')
args = parser.parse_args()

requirements = set()
for req_file in get_requirement_files(args.r):
requirements.update(load_requirements(req_file))

if args.r:
for req_file in get_requirement_files(args.r):
requirements.update(load_requirements(req_file))
elif args.p:
requirements.update(load_pipfile(args.p))
else:
parser.print_help()
exit(1)

pt = PrettyTable()
pt.field_names = ['Library', 'Current Version', 'Latest Version', 'Libyears behind']
total_days = 0

for req in requirements:
name, version, version_lt = get_requirement_name_and_version(req)
if not name:
continue

if not version and not version_lt:
continue

v, lv, days = get_lib_days(name, version, version_lt)
if v and days > 0:
pt.add_row([name, v, lv, str(round(days / 365, 2))])
Expand All @@ -42,7 +51,7 @@ def main():
else:
print(pt)
print("Your system is %s libyears behind" % str(round(total_days / 365, 2)))



if __name__ == "__main__":
Expand Down
29 changes: 29 additions & 0 deletions libyear/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os
import re

from pipfile import Pipfile


REQUIREMENT_NAME_RE = r'^([^=><]+)'
REQUIREMENT_VERSION_LT_RE = r'<([^$,]*)'
REQUIREMENT_VERSION_LTE_RE = r'[<=]=([^$,]*)'
Expand Down Expand Up @@ -67,3 +70,29 @@ def load_requirements(*requirements_paths):
if is_requirement(line)
)
return list(requirements)


def load_pipfile(pipfile_path):
"""
Load all requirements from the specified Pipfile.
Returns a list of requirement strings.
"""
requirements = set()
parsed_data = Pipfile.load(pipfile_path)

for package, version in parsed_data.data['default'].items():
# Version not specified, assume latest
if version == '*':
requirements.add(package)
continue

# If extra info is provided, use just version
# Ignore editable entries (e.g. git repos)
if isinstance(version, dict):
if 'version' in version.keys():
requirements.add(f'{package}{version["version"]}')
continue

requirements.add(f'{package}{version}')

return list(requirements)
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"requests>=2.0.0",
"prettytable>=0.7.2",
"python-dateutil>=2.7.0",
"pipfile",
],
setup_requires=["pytest-runner"],
)
18 changes: 18 additions & 0 deletions tests/data/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
"flake8" = "==3.7.8"
"pytest-flake8" = "==1.0.4"
pytest = "==3.10.1"

[packages]
requests = ">=2.0.0"
prettytable = ">=0.7.2"
idna = "==2.7"
docker = "<=4.4.4"
toml = "*"
random_lib1 = { git = "https://github.com/example/repo.git", ref = "1.0.0"}
random_lib2 = { version = "==2.0.0", extras = ["foo", "bar"] }
8 changes: 7 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from libyear.utils import get_requirement_name_and_version, load_requirements
from libyear.utils import get_requirement_name_and_version, load_requirements, load_pipfile


def test_loads_from_requirements_file_with_hashes():
Expand All @@ -15,3 +15,9 @@ def test_gets_name_and_version_from_requirements_file_with_hashes():
}

assert ("appdirs", "1.4.3", None) in results


def test_loads_from_pipfile():
path = Path(__file__).parent / "data" / "Pipfile"
assert set(load_pipfile(path)) == set(
['idna==2.7', 'prettytable>=0.7.2', 'toml', 'requests>=2.0.0', 'docker<=4.4.4', 'random_lib2==2.0.0'])