Skip to content

Commit

Permalink
Fix (finish implementation) memoization wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
arkq committed Jan 1, 2020
1 parent ad47aad commit 6d02a13
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 25 deletions.
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License

Copyright (c) 2017-2019 Arkadiusz Bokowy <[email protected]>
Copyright (c) 2017-2020 Arkadiusz Bokowy <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
25 changes: 13 additions & 12 deletions src/flake8_requirements/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ def memoize(f):
"""Cache value returned by the function."""
@wraps(f)
def w(*args, **kw):
memoize.mem[f] = v = f(*args, **kw)
return v
if f not in memoize.mem:
memoize.mem[f] = f(*args, **kw)
return memoize.mem[f]
return w


Expand Down Expand Up @@ -303,16 +304,6 @@ def parse_options(cls, options):
}
cls.requirements_max_depth = options.requirements_max_depth

@classmethod
@memoize
def get_requirements(cls):
"""Get package requirements."""
if not os.path.exists("requirements.txt"):
LOG.debug("No requirements.txt file")
return ()
return tuple(parse_requirements(cls.resolve_requirement(
"-r requirements.txt", cls.requirements_max_depth + 1)))

@classmethod
def resolve_requirement(cls, requirement, max_depth=0):
"""Resolves flags like -r in an individual requirement line."""
Expand All @@ -337,6 +328,16 @@ def resolve_requirement(cls, requirement, max_depth=0):

return [requirement]

@classmethod
@memoize
def get_requirements(cls):
"""Get package requirements."""
if not os.path.exists("requirements.txt"):
LOG.debug("No requirements.txt file")
return ()
return tuple(parse_requirements(cls.resolve_requirement(
"-r requirements.txt", cls.requirements_max_depth + 1)))

@classmethod
@memoize
def get_setup(cls):
Expand Down
32 changes: 20 additions & 12 deletions test/test_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pkg_resources import parse_requirements

from flake8_requirements.checker import Flake8Checker
from flake8_requirements.checker import memoize

try:
from unittest import mock
Expand Down Expand Up @@ -72,68 +73,75 @@ def test_resolve_requirement_with_file_recursion(self):

def test_init_with_no_requirements(self):
with mock.patch("os.path.exists", return_value=False) as exists:
with mock.patch(builtins_open, mock.mock_open()) as m:
checker = Flake8Checker(None, None)
self.assertEqual(checker.requirements, ())
m.assert_called_once_with("setup.py")
memoize.mem = {}
checker = Flake8Checker(None, None)
requirements = checker.get_requirements()
self.assertEqual(requirements, ())
exists.assert_called_once_with("requirements.txt")

def test_init_with_simple_requirements(self):
requirements_content = "foo >= 1.0.0\nbar <= 1.0.0\n"
content = "foo >= 1.0.0\nbar <= 1.0.0\n"
setup_content = ""

with mock.patch("os.path.exists", return_value=True):
with mock.patch(builtins_open, mock.mock_open()) as m:
m.side_effect = (
mock.mock_open(read_data=requirements_content).return_value,
mock.mock_open(read_data=content).return_value,
mock.mock_open(read_data=setup_content).return_value,
)

memoize.mem = {}
checker = Flake8Checker(None, None)
requirements = checker.get_requirements()

self.assertEqual(
sorted(checker.requirements, key=lambda x: x.project_name),
sorted(requirements, key=lambda x: x.project_name),
sorted(parse_requirements([
"foo >= 1.0.0",
"bar <= 1.0.0",
]), key=lambda x: x.project_name),
)

def test_init_with_recursive_requirements_beyond_max_depth(self):
requirements_content = "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"
content = "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"
inner_content = "# inner\nbaz\n\nqux\n"
setup_content = ""

with mock.patch("os.path.exists", return_value=True):
with mock.patch(builtins_open, mock.mock_open()) as m:
m.side_effect = (
mock.mock_open(read_data=requirements_content).return_value,
mock.mock_open(read_data=content).return_value,
mock.mock_open(read_data=inner_content).return_value,
mock.mock_open(read_data=setup_content).return_value,
)

with self.assertRaises(RuntimeError):
try:
memoize.mem = {}
Flake8Checker.requirements_max_depth = 0
Flake8Checker(None, None)
finally:
Flake8Checker.requirements_max_depth = 1

def test_init_with_recursive_requirements(self):
requirements_content = "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"
content = "foo >= 1.0.0\n-r inner.txt\nbar <= 1.0.0\n"
inner_content = "# inner\nbaz\n\nqux\n"
setup_content = ""

with mock.patch("os.path.exists", return_value=True):
with mock.patch(builtins_open, mock.mock_open()) as m:
m.side_effect = (
mock.mock_open(read_data=requirements_content).return_value,
mock.mock_open(read_data=content).return_value,
mock.mock_open(read_data=inner_content).return_value,
mock.mock_open(read_data=setup_content).return_value,
)

memoize.mem = {}
checker = Flake8Checker(None, None)
requirements = checker.get_requirements()

self.assertEqual(
sorted(checker.requirements, key=lambda x: x.project_name),
sorted(requirements, key=lambda x: x.project_name),
sorted(parse_requirements([
"foo >= 1.0.0",
"baz",
Expand Down

0 comments on commit 6d02a13

Please sign in to comment.