2
0
Fork 0

Compare commits

..

No commits in common. "bb7a83a73c327be68d2cb1c7c459c5a10fec6909" and "58c3f781df64f1804293e29ff9042e77ec98c4a5" have entirely different histories.

4 changed files with 36 additions and 103 deletions

View file

@ -5,12 +5,6 @@ All notable changes to WuttJamaican will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.12.0 (2024-08-15)
### Feat
- add util function `get_class_hierarchy()`
## v0.11.1 (2024-08-15) ## v0.11.1 (2024-08-15)
### Fix ### Fix

View file

@ -6,7 +6,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "WuttJamaican" name = "WuttJamaican"
version = "0.12.0" version = "0.11.1"
description = "Base package for Wutta Framework" description = "Base package for Wutta Framework"
readme = "README.md" readme = "README.md"
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]

View file

@ -38,46 +38,6 @@ log = logging.getLogger(__name__)
UNSPECIFIED = object() UNSPECIFIED = object()
def get_class_hierarchy(klass, topfirst=True):
"""
Returns a list of all classes in the inheritance chain for the
given class.
For instance::
class A:
pass
class B(A):
pass
class C(B):
pass
get_class_hierarchy(C)
# -> [A, B, C]
:param klass: The reference class. The list of classes returned
will include this class and all its parents.
:param topfirst: Whether the returned list should be sorted in a
"top first" way, e.g. A) grandparent, B) parent, C) child.
This is the default but pass ``False`` to get the reverse.
"""
hierarchy = []
def traverse(cls):
if cls is not object:
hierarchy.append(cls)
for parent in cls.__bases__:
traverse(parent)
traverse(klass)
if topfirst:
hierarchy.reverse()
return hierarchy
def load_entry_points(group, ignore_errors=False): def load_entry_points(group, ignore_errors=False):
""" """
Load a set of ``setuptools``-style entry points. Load a set of ``setuptools``-style entry points.

View file

@ -6,41 +6,20 @@ from unittest.mock import patch, MagicMock
import pytest import pytest
from wuttjamaican import util as mod from wuttjamaican import util
class A: pass
class B(A): pass
class C(B): pass
class TestGetClassHierarchy(TestCase):
def test_basic(self):
classes = mod.get_class_hierarchy(A)
self.assertEqual(classes, [A])
classes = mod.get_class_hierarchy(B)
self.assertEqual(classes, [A, B])
classes = mod.get_class_hierarchy(C)
self.assertEqual(classes, [A, B, C])
classes = mod.get_class_hierarchy(C, topfirst=False)
self.assertEqual(classes, [C, B, A])
class TestLoadEntryPoints(TestCase): class TestLoadEntryPoints(TestCase):
def test_empty(self): def test_empty(self):
# empty set returned for unknown group # empty set returned for unknown group
result = mod.load_entry_points('this_should_never_exist!!!!!!') result = util.load_entry_points('this_should_never_exist!!!!!!')
self.assertEqual(result, {}) self.assertEqual(result, {})
def test_basic(self): def test_basic(self):
# load some entry points which should "always" be present, # load some entry points which should "always" be present,
# even in a testing environment. basic sanity check # even in a testing environment. basic sanity check
result = mod.load_entry_points('console_scripts', ignore_errors=True) result = util.load_entry_points('console_scripts', ignore_errors=True)
self.assertTrue(len(result) >= 1) self.assertTrue(len(result) >= 1)
self.assertIn('pip', result) self.assertIn('pip', result)
@ -66,7 +45,7 @@ class TestLoadEntryPoints(TestCase):
# load some entry points which should "always" be present, # load some entry points which should "always" be present,
# even in a testing environment. basic sanity check # even in a testing environment. basic sanity check
result = mod.load_entry_points('console_scripts', ignore_errors=True) result = util.load_entry_points('console_scripts', ignore_errors=True)
self.assertTrue(len(result) >= 1) self.assertTrue(len(result) >= 1)
self.assertIn('pytest', result) self.assertIn('pytest', result)
@ -103,7 +82,7 @@ class TestLoadEntryPoints(TestCase):
# load some entry points which should "always" be present, # load some entry points which should "always" be present,
# even in a testing environment. basic sanity check # even in a testing environment. basic sanity check
result = mod.load_entry_points('console_scripts', ignore_errors=True) result = util.load_entry_points('console_scripts', ignore_errors=True)
self.assertTrue(len(result) >= 1) self.assertTrue(len(result) >= 1)
self.assertIn('pytest', result) self.assertIn('pytest', result)
@ -125,7 +104,7 @@ class TestLoadEntryPoints(TestCase):
with patch.dict('sys.modules', **{'importlib': importlib}): with patch.dict('sys.modules', **{'importlib': importlib}):
# empty set returned if errors suppressed # empty set returned if errors suppressed
result = mod.load_entry_points('wuttatest.thingers', ignore_errors=True) result = util.load_entry_points('wuttatest.thingers', ignore_errors=True)
self.assertEqual(result, {}) self.assertEqual(result, {})
importlib.metadata.entry_points.assert_called_once_with() importlib.metadata.entry_points.assert_called_once_with()
entry_points.select.assert_called_once_with(group='wuttatest.thingers') entry_points.select.assert_called_once_with(group='wuttatest.thingers')
@ -135,7 +114,7 @@ class TestLoadEntryPoints(TestCase):
importlib.metadata.entry_points.reset_mock() importlib.metadata.entry_points.reset_mock()
entry_points.select.reset_mock() entry_points.select.reset_mock()
entry_point.load.reset_mock() entry_point.load.reset_mock()
self.assertRaises(NotImplementedError, mod.load_entry_points, 'wuttatest.thingers') self.assertRaises(NotImplementedError, util.load_entry_points, 'wuttatest.thingers')
importlib.metadata.entry_points.assert_called_once_with() importlib.metadata.entry_points.assert_called_once_with()
entry_points.select.assert_called_once_with(group='wuttatest.thingers') entry_points.select.assert_called_once_with(group='wuttatest.thingers')
entry_point.load.assert_called_once_with() entry_point.load.assert_called_once_with()
@ -144,96 +123,96 @@ class TestLoadEntryPoints(TestCase):
class TestLoadObject(TestCase): class TestLoadObject(TestCase):
def test_missing_spec(self): def test_missing_spec(self):
self.assertRaises(ValueError, mod.load_object, None) self.assertRaises(ValueError, util.load_object, None)
def test_basic(self): def test_basic(self):
result = mod.load_object('unittest:TestCase') result = util.load_object('unittest:TestCase')
self.assertIs(result, TestCase) self.assertIs(result, TestCase)
class TestMakeUUID(TestCase): class TestMakeUUID(TestCase):
def test_basic(self): def test_basic(self):
uuid = mod.make_uuid() uuid = util.make_uuid()
self.assertEqual(len(uuid), 32) self.assertEqual(len(uuid), 32)
class TestParseBool(TestCase): class TestParseBool(TestCase):
def test_null(self): def test_null(self):
self.assertIsNone(mod.parse_bool(None)) self.assertIsNone(util.parse_bool(None))
def test_bool(self): def test_bool(self):
self.assertTrue(mod.parse_bool(True)) self.assertTrue(util.parse_bool(True))
self.assertFalse(mod.parse_bool(False)) self.assertFalse(util.parse_bool(False))
def test_string_true(self): def test_string_true(self):
self.assertTrue(mod.parse_bool('true')) self.assertTrue(util.parse_bool('true'))
self.assertTrue(mod.parse_bool('yes')) self.assertTrue(util.parse_bool('yes'))
self.assertTrue(mod.parse_bool('y')) self.assertTrue(util.parse_bool('y'))
self.assertTrue(mod.parse_bool('on')) self.assertTrue(util.parse_bool('on'))
self.assertTrue(mod.parse_bool('1')) self.assertTrue(util.parse_bool('1'))
def test_string_false(self): def test_string_false(self):
self.assertFalse(mod.parse_bool('false')) self.assertFalse(util.parse_bool('false'))
self.assertFalse(mod.parse_bool('no')) self.assertFalse(util.parse_bool('no'))
self.assertFalse(mod.parse_bool('n')) self.assertFalse(util.parse_bool('n'))
self.assertFalse(mod.parse_bool('off')) self.assertFalse(util.parse_bool('off'))
self.assertFalse(mod.parse_bool('0')) self.assertFalse(util.parse_bool('0'))
# nb. assume false for unrecognized input # nb. assume false for unrecognized input
self.assertFalse(mod.parse_bool('whatever-else')) self.assertFalse(util.parse_bool('whatever-else'))
class TestParseList(TestCase): class TestParseList(TestCase):
def test_null(self): def test_null(self):
value = mod.parse_list(None) value = util.parse_list(None)
self.assertIsInstance(value, list) self.assertIsInstance(value, list)
self.assertEqual(len(value), 0) self.assertEqual(len(value), 0)
def test_list_instance(self): def test_list_instance(self):
mylist = [] mylist = []
value = mod.parse_list(mylist) value = util.parse_list(mylist)
self.assertIs(value, mylist) self.assertIs(value, mylist)
def test_single_value(self): def test_single_value(self):
value = mod.parse_list('foo') value = util.parse_list('foo')
self.assertEqual(len(value), 1) self.assertEqual(len(value), 1)
self.assertEqual(value[0], 'foo') self.assertEqual(value[0], 'foo')
def test_single_value_padded_by_spaces(self): def test_single_value_padded_by_spaces(self):
value = mod.parse_list(' foo ') value = util.parse_list(' foo ')
self.assertEqual(len(value), 1) self.assertEqual(len(value), 1)
self.assertEqual(value[0], 'foo') self.assertEqual(value[0], 'foo')
def test_slash_is_not_a_separator(self): def test_slash_is_not_a_separator(self):
value = mod.parse_list('/dev/null') value = util.parse_list('/dev/null')
self.assertEqual(len(value), 1) self.assertEqual(len(value), 1)
self.assertEqual(value[0], '/dev/null') self.assertEqual(value[0], '/dev/null')
def test_multiple_values_separated_by_whitespace(self): def test_multiple_values_separated_by_whitespace(self):
value = mod.parse_list('foo bar baz') value = util.parse_list('foo bar baz')
self.assertEqual(len(value), 3) self.assertEqual(len(value), 3)
self.assertEqual(value[0], 'foo') self.assertEqual(value[0], 'foo')
self.assertEqual(value[1], 'bar') self.assertEqual(value[1], 'bar')
self.assertEqual(value[2], 'baz') self.assertEqual(value[2], 'baz')
def test_multiple_values_separated_by_commas(self): def test_multiple_values_separated_by_commas(self):
value = mod.parse_list('foo,bar,baz') value = util.parse_list('foo,bar,baz')
self.assertEqual(len(value), 3) self.assertEqual(len(value), 3)
self.assertEqual(value[0], 'foo') self.assertEqual(value[0], 'foo')
self.assertEqual(value[1], 'bar') self.assertEqual(value[1], 'bar')
self.assertEqual(value[2], 'baz') self.assertEqual(value[2], 'baz')
def test_multiple_values_separated_by_whitespace_and_commas(self): def test_multiple_values_separated_by_whitespace_and_commas(self):
value = mod.parse_list(' foo, bar baz') value = util.parse_list(' foo, bar baz')
self.assertEqual(len(value), 3) self.assertEqual(len(value), 3)
self.assertEqual(value[0], 'foo') self.assertEqual(value[0], 'foo')
self.assertEqual(value[1], 'bar') self.assertEqual(value[1], 'bar')
self.assertEqual(value[2], 'baz') self.assertEqual(value[2], 'baz')
def test_multiple_values_separated_by_whitespace_and_commas_with_some_quoting(self): def test_multiple_values_separated_by_whitespace_and_commas_with_some_quoting(self):
value = mod.parse_list(""" value = util.parse_list("""
foo foo
"C:\\some path\\with spaces\\and, a comma", "C:\\some path\\with spaces\\and, a comma",
baz baz
@ -244,7 +223,7 @@ class TestParseList(TestCase):
self.assertEqual(value[2], 'baz') self.assertEqual(value[2], 'baz')
def test_multiple_values_separated_by_whitespace_and_commas_with_single_quotes(self): def test_multiple_values_separated_by_whitespace_and_commas_with_single_quotes(self):
value = mod.parse_list(""" value = util.parse_list("""
foo foo
'C:\\some path\\with spaces\\and, a comma', 'C:\\some path\\with spaces\\and, a comma',
baz baz
@ -258,5 +237,5 @@ class TestParseList(TestCase):
class TestMakeTitle(TestCase): class TestMakeTitle(TestCase):
def test_basic(self): def test_basic(self):
text = mod.make_title('foo_bar') text = util.make_title('foo_bar')
self.assertEqual(text, "Foo Bar") self.assertEqual(text, "Foo Bar")