# Path: meta_package_manager/pool.py
# ALL_MANAGER_IDS = tuple(sorted(pool()))
# 
# @cached(LRI(max_size=1))
# def pool():
#     """Search for package manager definitions locally and store them into an
#     internal register.
# 
#     Is considered valid package manager, definitions classes which:
#         1 - are located in the `managers` subfolder, and
#         2 - are sub-classes of PackageManager, and
#         3 - are not virtual (i.e. have a non null `cli_names` property).
#     """
#     register = {}
# 
#     for py_file in Path(__file__).parent.joinpath(MANAGER_SUBFOLDER).glob("*.py"):
#         logger.debug(f"Search manager definitions in {py_file}")
#         module = import_module(
#             f".{MANAGER_SUBFOLDER}.{py_file.stem}", package=__package__
#         )
# 
#         for _, klass in inspect.getmembers(module, inspect.isclass):
#             if issubclass(klass, PackageManager) and not klass.virtual:
#                 logger.debug(f"Found {klass!r}")
#                 manager = klass()
#                 register[manager.id] = manager
#             else:
#                 logger.debug(f"{klass!r} is not a valid manager definition")
# 
#     return register
# 
# Path: meta_package_manager/version.py
# class TokenizedString:
# 
#     """Tokenize a string for user-friendly sorting.
# 
#     Essentially a wrapper around a tuple of `Token` instances.
#     """
# 
#     separator = None
#     string = None
#     tokens = ()
# 
#     def __hash__(self):
#         """A `TokenizedString` is made unique by its original string and tuple
#         of parsed tokens."""
#         return hash((self.string, self.separator, self.tokens))
# 
#     def __new__(cls, value, *args, **kwargs):
#         """Return same object if a TokenizedString parameter is used at
#         instanciation.
#         """
#         if isinstance(value, TokenizedString):
#             return value
#         return super().__new__(cls)
# 
#     def __init__(self, value, separator="-"):
#         if isinstance(value, TokenizedString):
#             # Skip initialization for instance of the class.
#             return
#         if isinstance(value, int):
#             self.string = str(value)
#         elif isinstance(value, str):
#             self.string = value.strip()
#         else:
#             raise TypeError(f"{type(value)} not supported")
#         self.tokens = tuple(self.tokenize(self.string))
#         self.separator = separator
# 
#     def __repr__(self):
#         return f"<TokenizedString {self.string} => {self.tokens}>"
# 
#     def __str__(self):
#         return self.string
# 
#     def pretty_print(self):
#         return self.separator.join(map(str, self.tokens))
# 
#     @classmethod
#     def tokenize(cls, string):
#         """Tokenize a string: ignore case and split at each non-alphanumeric
#         characters.
# 
#         Returns a tuple of Token instances. Which allows for comparison between
#         strings and integers. That way we get natural, user-friendly sorting of
#         version numbers. That we can get with simple Python, see:
# 
#             >>> '2019.0.1' > '9.3'
#             False
#             >>> ('2019', '0', '1') > ('9', '3')
#             False
#             >>> (2019, 0, 1) > (9, 3)
#             True
#         """
#         normalized_str = strutils.asciify(string).lower().decode()
# 
#         for segment in ALNUM_EXTRACTOR.split(normalized_str):
#             if segment.isalnum():
#                 yield Token(segment)
# 
#     """ TokenizedString can be compared as tuples. """
# 
#     def __iter__(self):
#         """`TokenizedString` essentially are a wrapper around a tuple of
#         `Token`.
#         """
#         return iter(self.tokens)
# 
#     def __eq__(self, other):
#         if isinstance(other, (TokenizedString, tuple)):
#             return tuple(self) == tuple(other)
# 
#     def __ne__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) != tuple(other)
# 
#     def __gt__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) > tuple(other)
# 
#     def __lt__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) < tuple(other)
# 
#     def __ge__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) >= tuple(other)
# 
#     def __le__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) <= tuple(other)


import re
import pytest
from operator import attrgetter
from pathlib import Path, PurePath
from string import ascii_letters, ascii_lowercase, digits
from types import MethodType
from click_extra.platform import OS_DEFINITIONS
from ..pool import ALL_MANAGER_IDS, pool
from ..version import TokenizedString
        except Exception as excpt:
            assert isinstance(excpt, NotImplementedError)
        else:
            assert isinstance(matches, dict)
            for pkg in matches.values():
                assert isinstance(pkg, dict)
                assert set(pkg) == {"id", "name", "latest_version"}
                assert isinstance(pkg["id"], str)
                assert isinstance(pkg["name"], str)
                if pkg["latest_version"] is not None:
                    assert isinstance(pkg["latest_version"], TokenizedString)


@all_managers
def test_outdated_type(manager):
    """Check that all outdated operations returns a dict of dicts."""
    if manager.available:
        try:
            result = manager.outdated
        except Exception as excpt:
            assert isinstance(excpt, NotImplementedError)
        else:
            assert isinstance(result, dict)
            for pkg in manager.outdated.values():
                assert isinstance(pkg, dict)
                assert set(pkg) == {"id", "name", "installed_version", "latest_version"}
                assert isinstance(pkg["id"], str)
                assert isinstance(pkg["name"], str)
                if pkg["installed_version"] is not None:
                    assert isinstance(pkg["installed_version"], TokenizedString)

# Path: meta_package_manager/pool.py
# ALL_MANAGER_IDS = tuple(sorted(pool()))
# 
# @cached(LRI(max_size=1))
# def pool():
#     """Search for package manager definitions locally and store them into an
#     internal register.
# 
#     Is considered valid package manager, definitions classes which:
#         1 - are located in the `managers` subfolder, and
#         2 - are sub-classes of PackageManager, and
#         3 - are not virtual (i.e. have a non null `cli_names` property).
#     """
#     register = {}
# 
#     for py_file in Path(__file__).parent.joinpath(MANAGER_SUBFOLDER).glob("*.py"):
#         logger.debug(f"Search manager definitions in {py_file}")
#         module = import_module(
#             f".{MANAGER_SUBFOLDER}.{py_file.stem}", package=__package__
#         )
# 
#         for _, klass in inspect.getmembers(module, inspect.isclass):
#             if issubclass(klass, PackageManager) and not klass.virtual:
#                 logger.debug(f"Found {klass!r}")
#                 manager = klass()
#                 register[manager.id] = manager
#             else:
#                 logger.debug(f"{klass!r} is not a valid manager definition")
# 
#     return register
# 
# Path: meta_package_manager/version.py
# class TokenizedString:
# 
#     """Tokenize a string for user-friendly sorting.
# 
#     Essentially a wrapper around a tuple of `Token` instances.
#     """
# 
#     separator = None
#     string = None
#     tokens = ()
# 
#     def __hash__(self):
#         """A `TokenizedString` is made unique by its original string and tuple
#         of parsed tokens."""
#         return hash((self.string, self.separator, self.tokens))
# 
#     def __new__(cls, value, *args, **kwargs):
#         """Return same object if a TokenizedString parameter is used at
#         instanciation.
#         """
#         if isinstance(value, TokenizedString):
#             return value
#         return super().__new__(cls)
# 
#     def __init__(self, value, separator="-"):
#         if isinstance(value, TokenizedString):
#             # Skip initialization for instance of the class.
#             return
#         if isinstance(value, int):
#             self.string = str(value)
#         elif isinstance(value, str):
#             self.string = value.strip()
#         else:
#             raise TypeError(f"{type(value)} not supported")
#         self.tokens = tuple(self.tokenize(self.string))
#         self.separator = separator
# 
#     def __repr__(self):
#         return f"<TokenizedString {self.string} => {self.tokens}>"
# 
#     def __str__(self):
#         return self.string
# 
#     def pretty_print(self):
#         return self.separator.join(map(str, self.tokens))
# 
#     @classmethod
#     def tokenize(cls, string):
#         """Tokenize a string: ignore case and split at each non-alphanumeric
#         characters.
# 
#         Returns a tuple of Token instances. Which allows for comparison between
#         strings and integers. That way we get natural, user-friendly sorting of
#         version numbers. That we can get with simple Python, see:
# 
#             >>> '2019.0.1' > '9.3'
#             False
#             >>> ('2019', '0', '1') > ('9', '3')
#             False
#             >>> (2019, 0, 1) > (9, 3)
#             True
#         """
#         normalized_str = strutils.asciify(string).lower().decode()
# 
#         for segment in ALNUM_EXTRACTOR.split(normalized_str):
#             if segment.isalnum():
#                 yield Token(segment)
# 
#     """ TokenizedString can be compared as tuples. """
# 
#     def __iter__(self):
#         """`TokenizedString` essentially are a wrapper around a tuple of
#         `Token`.
#         """
#         return iter(self.tokens)
# 
#     def __eq__(self, other):
#         if isinstance(other, (TokenizedString, tuple)):
#             return tuple(self) == tuple(other)
# 
#     def __ne__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) != tuple(other)
# 
#     def __gt__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) > tuple(other)
# 
#     def __lt__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) < tuple(other)
# 
#     def __ge__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) >= tuple(other)
# 
#     def __le__(self, other):
#         if isinstance(other, TokenizedString):
#             return tuple(self) <= tuple(other)


# Path: meta_package_manager/tests/test_managers.py
import re
import pytest
from operator import attrgetter
from pathlib import Path, PurePath
from string import ascii_letters, ascii_lowercase, digits
from types import MethodType
from click_extra.platform import OS_DEFINITIONS
from ..pool import ALL_MANAGER_IDS, pool
from ..version import TokenizedString

        except Exception as excpt:
            assert isinstance(excpt, NotImplementedError)
        else:
            assert isinstance(matches, dict)
            for pkg in matches.values():
                assert isinstance(pkg, dict)
                assert set(pkg) == {"id", "name", "latest_version"}
                assert isinstance(pkg["id"], str)
                assert isinstance(pkg["name"], str)
                if pkg["latest_version"] is not None:
                    assert isinstance(pkg["latest_version"], TokenizedString)


@all_managers
def test_outdated_type(manager):
    """Check that all outdated operations returns a dict of dicts."""
    if manager.available:
        try:
            result = manager.outdated
        except Exception as excpt:
            assert isinstance(excpt, NotImplementedError)
        else:
            assert isinstance(result, dict)
            for pkg in manager.outdated.values():
                assert isinstance(pkg, dict)
                assert set(pkg) == {"id", "name", "installed_version", "latest_version"}
                assert isinstance(pkg["id"], str)
                assert isinstance(pkg["name"], str)
                if pkg["installed_version"] is not None:
                    assert isinstance(pkg["installed_version"], TokenizedString)

                assert isinstance(pkg["latest_version"], TokenizedString)