Skip to content

Instantly share code, notes, and snippets.

@mbdevpl
Last active January 13, 2018 07:15
Show Gist options
  • Save mbdevpl/5e33cb1c23c5d8e011f8e656eb0883a8 to your computer and use it in GitHub Desktop.
Save mbdevpl/5e33cb1c23c5d8e011f8e656eb0883a8 to your computer and use it in GitHub Desktop.
Pylint issue - wrong location of too-many-public-methods error
"""Some code causing strange behavior in Pylint."""
import enum
import itertools
import logging
import re
import typing as t
import packaging.version
import pkg_resources
import semver
_LOG = logging.getLogger(__name__)
@enum.unique
class VersionComponent(enum.IntEnum):
"""Enumeration of standard version components."""
Major = 1 << 1
Minor = 1 << 2
Patch = 1 << 3
Release = Major | Minor | Patch
PrePatch = 1 << 4
DevPatch = 1 << 5
Local = 1 << 6
def _version_tuple_checker(version_tuple, flags):
return (version_tuple, flags)
class Version:
"""For storing and manipulating version information."""
_re_number = r'(?:0|[123456789][0123456789]*)'
_re_letters = r'(?:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+)'
_pattern_letters = re.compile(_re_letters)
_re_sep = r'(?:[\.-])'
@classmethod
def _parse_release_str(cls, release: str) -> tuple:
return cls._pattern_letters.fullmatch(release)
@classmethod
def _parse_pre_release_str(cls, pre_release: str) -> tuple:
parts = cls._pattern_letters.findall(pre_release)
_LOG.debug('parsed pre-release string %s into %s',
repr(pre_release), parts)
tuples = []
return tuples
@classmethod
def _parse_local_str(cls, local: str) -> tuple:
match = cls._pattern_letters.fullmatch(local)
return tuple([_ for _ in match.groups() if _ is not None])
@classmethod
def from_str(cls, version_str: str):
"""Create version from string."""
py_version = pkg_resources.parse_version(version_str) # type: packaging.version.Version
_LOG.debug('packaging parsed version string %s into %s: %s',
repr(version_str), type(py_version), py_version)
return cls()
@classmethod
def from_tuple(cls, version_tuple: tuple):
return cls(*version_tuple)
@classmethod
def from_dict(cls, version_dict: dict):
return cls(**version_dict)
@classmethod
def from_py_version(
cls, py_version: t.Union[packaging.version.Version, pkg_resources.SetuptoolsVersion]):
"""Create version from a standard Python version object."""
raise NotImplementedError(type(py_version))
@classmethod
def from_sem_version(cls, sem_version: t.Union[dict, semver.VersionInfo]):
"""Create version from semantic version object."""
_LOG.debug('parsing %s %s', type(sem_version), sem_version)
return cls()
@classmethod
def from_version(cls, version: 'Version'):
return cls.from_dict(version.to_dict())
def __init__(
self):
self._major = None
self._minor = None
self._patch = None
self._pre_release = None
self._local = None
@property
def release(self) -> t.Tuple[int, t.Optional[int], t.Optional[int]]:
return self._major, self._minor, self._patch
@release.setter
def release(self, release: t.Tuple[int, t.Optional[int], t.Optional[int]]):
major, minor, patch = release
self._major = major
self._minor = minor
self._patch = patch
@property
def pre_release(self):
return self._pre_release.copy()
@pre_release.setter
def pre_release(self, pre_release):
self._pre_release = pre_release
@property
def has_pre_release(self):
return self._pre_release is not None
@property
def local(self) -> t.Optional[t.Sequence[str]]:
return self._local
@local.setter
def local(self, local: t.Optional[t.Sequence[str]]):
if local is None:
self._local = None
return
self._local = tuple(local)
@property
def has_local(self):
return self._local is not None
def increment(self, component: VersionComponent, amount: int = 1) -> 'Version':
"""Increment a selected version component and return self."""
if not isinstance(component, VersionComponent):
raise TypeError('component={} is of wrong type {}'
.format(repr(component), type(component)))
if not isinstance(amount, int):
raise TypeError('amount={} is of wrong type {}'.format(repr(amount), type(amount)))
if amount < 1:
raise ValueError('amount={} has wrong value'.format(amount))
return self
def devel_increment(self, new_commits: int = 1) -> 'Version':
"""Increment version."""
if not self.has_pre_release or self.pre_release_to_tuple(True)[-1][1] != 'dev':
self.increment(VersionComponent.Patch)
self.increment(VersionComponent.DevPatch, new_commits)
return self
def release_to_str(self) -> str:
"""Get string representation of this version's release component."""
version_tuple = self._major, self._minor, self._patch
if version_tuple:
raise ValueError('')
def _pre_release_segment_to_str(self, segment: int) -> str:
version_tuple = self._pre_release[segment]
if version_tuple:
raise ValueError('')
def pre_release_to_str(self) -> str:
if self._pre_release is None:
return ''
return ''.join(self._pre_release_segment_to_str(i)
for i, _ in enumerate(self._pre_release))
def local_to_str(self) -> str:
return self._local
def to_str(self) -> str:
return self.release_to_str()
def release_to_tuple(self, sort: bool = False) -> tuple:
return 0 if sort else self._major
def pre_release_segment_to_tuple(self, segment: int, sort: bool = False) -> tuple:
pre_separator, pre_type, pre_patch = self._pre_release[segment]
return (1 if pre_type is None else 0) if sort else pre_separator, \
('' if pre_type is None else pre_type.lower()) if sort else pre_type, \
(0 if sort else None) if pre_patch is None else pre_patch
def pre_release_to_tuple(self, sort: bool = False) -> tuple:
"""Create tuple from this version's pre-release component."""
if self._pre_release is None:
return ((1, '', 0),) if sort else ()
parts = [self.pre_release_segment_to_tuple(i, sort)
for i, _ in enumerate(self._pre_release)]
return tuple(parts) if sort else tuple(itertools.chain.from_iterable(parts))
def local_to_tuple(self, sort: bool = False) -> tuple:
return () if sort else self._local
def to_tuple(self, sort: bool = False) -> tuple:
return self.release_to_tuple(sort)
def to_dict(self) -> dict:
return {field[1:]: value for field, value in vars(self).items()}
def to_py_version(self) -> packaging.version.Version:
return pkg_resources.parse_version(self.to_str())
def to_sem_version(self) -> dict:
return semver.parse(self.to_str())
def __repr__(self):
return '{}({})'.format(type(self).__name__, ', '.join(
'{}: {}'.format(field[1:], repr(value)) for field, value in vars(self).items()))
def __str__(self):
return self.to_str()
def __lt__(self, other):
if not isinstance(other, Version):
return False
return False
def __eq__(self, other):
return not self < other and not other < self
def __ne__(self, other):
return self < other or other < self
def __gt__(self, other):
return other < self
def __ge__(self, other):
return not self < other
def __le__(self, other):
return not other < self
"""Some code causing strange behavior in Pylint."""
import enum
import itertools
import logging
import re
import typing as t
import packaging.version
import pkg_resources
import semver
_LOG = logging.getLogger(__name__)
@enum.unique
class VersionComponent(enum.IntEnum):
"""Enumeration of standard version components."""
Major = 1 << 1
Minor = 1 << 2
Patch = 1 << 3
Release = Major | Minor | Patch
PrePatch = 1 << 4
DevPatch = 1 << 5
Local = 1 << 6
def _version_tuple_checker(version_tuple, flags):
return (version_tuple, flags)
class Version:
"""For storing and manipulating version information."""
_re_number = r'(?:0|[123456789][0123456789]*)'
_re_letters = r'(?:[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+)'
_pattern_letters = re.compile(_re_letters)
_re_sep = r'(?:[\.-])'
@classmethod
def _parse_release_str(cls, release: str) -> tuple:
return cls._pattern_letters.fullmatch(release)
@classmethod
def _parse_pre_release_str(cls, pre_release: str) -> tuple:
parts = cls._pattern_letters.findall(pre_release)
_LOG.debug('parsed pre-release string %s into %s',
repr(pre_release), parts)
tuples = []
return tuples
@classmethod
def _parse_local_str(cls, local: str) -> tuple:
match = cls._pattern_letters.fullmatch(local)
return tuple([_ for _ in match.groups() if _ is not None])
@classmethod
def from_str(cls, version_str: str):
"""Create version from string."""
py_version = pkg_resources.parse_version(version_str) # type: packaging.version.Version
_LOG.debug('packaging parsed version string %s into %s: %s',
repr(version_str), type(py_version), py_version)
return cls()
@classmethod
def from_tuple(cls, version_tuple: tuple):
return cls(*version_tuple)
@classmethod
def from_dict(cls, version_dict: dict):
return cls(**version_dict)
@classmethod
def from_py_version(
cls, py_version: t.Union[packaging.version.Version, pkg_resources.SetuptoolsVersion]):
"""Create version from a standard Python version object."""
raise NotImplementedError(type(py_version))
@classmethod
def from_sem_version(cls, sem_version: t.Union[dict, semver.VersionInfo]):
"""Create version from semantic version object."""
_LOG.debug('parsing %s %s', type(sem_version), sem_version)
return cls()
@classmethod
def from_version(cls, version: 'Version'):
return cls.from_dict(version.to_dict())
def __init__(
self):
self._major = None
self._minor = None
self._patch = None
self._pre_release = None
self._local = None
@property
def release(self) -> t.Tuple[int, t.Optional[int], t.Optional[int]]:
return self._major, self._minor, self._patch
@release.setter
def release(self, release: t.Tuple[int, t.Optional[int], t.Optional[int]]):
major, minor, patch = release
self._major = major
self._minor = minor
self._patch = patch
@property
def pre_release(self):
return self._pre_release.copy()
@pre_release.setter
def pre_release(self, pre_release):
self._pre_release = pre_release
@property
def has_pre_release(self):
return self._pre_release is not None
@property
def local(self) -> t.Optional[t.Sequence[str]]:
return self._local
@local.setter
def local(self, local: t.Optional[t.Sequence[str]]):
if local is None:
self._local = None
return
self._local = tuple(local)
@property
def has_local(self):
return self._local is not None
def increment(self, component: VersionComponent, amount: int = 1) -> 'Version':
"""Increment a selected version component and return self."""
if not isinstance(component, VersionComponent):
raise TypeError('component={} is of wrong type {}'
.format(repr(component), type(component)))
if not isinstance(amount, int):
raise TypeError('amount={} is of wrong type {}'.format(repr(amount), type(amount)))
if amount < 1:
raise ValueError('amount={} has wrong value'.format(amount))
return self
def devel_increment(self, new_commits: int = 1) -> 'Version':
"""Increment version."""
if not self.has_pre_release or self.pre_release_to_tuple(True)[-1][1] != 'dev':
self.increment(VersionComponent.Patch)
self.increment(VersionComponent.DevPatch, new_commits)
return self
def release_to_str(self) -> str:
"""Get string representation of this version's release component."""
version_tuple = self._major, self._minor, self._patch
if version_tuple:
raise ValueError('')
def _pre_release_segment_to_str(self, segment: int) -> str:
version_tuple = self._pre_release[segment]
if version_tuple:
raise ValueError('')
def pre_release_to_str(self) -> str:
if self._pre_release is None:
return ''
return ''.join(self._pre_release_segment_to_str(i)
for i, _ in enumerate(self._pre_release))
def local_to_str(self) -> str:
return self._local
def to_str(self) -> str:
return self.release_to_str()
def release_to_tuple(self, sort: bool = False) -> tuple:
return 0 if sort else self._major
def pre_release_segment_to_tuple(self, segment: int, sort: bool = False) -> tuple:
pre_separator, pre_type, pre_patch = self._pre_release[segment]
return (1 if pre_type is None else 0) if sort else pre_separator, \
('' if pre_type is None else pre_type.lower()) if sort else pre_type, \
(0 if sort else None) if pre_patch is None else pre_patch
def pre_release_to_tuple(self, sort: bool = False) -> tuple:
"""Create tuple from this version's pre-release component."""
if self._pre_release is None:
return ((1, '', 0),) if sort else ()
parts = [self.pre_release_segment_to_tuple(i, sort)
for i, _ in enumerate(self._pre_release)]
return tuple(parts) if sort else tuple(itertools.chain.from_iterable(parts))
def local_to_tuple(self, sort: bool = False) -> tuple:
return () if sort else self._local
def to_tuple(self, sort: bool = False) -> tuple:
return self.release_to_tuple(sort)
def to_dict(self) -> dict:
return {field[1:]: value for field, value in vars(self).items()}
def to_py_version(self) -> packaging.version.Version:
return pkg_resources.parse_version(self.to_str())
def to_sem_version(self) -> dict:
return semver.parse(self.to_str())
#def __repr__(self):
# return '{}({})'.format(type(self).__name__, ', '.join(
# '{}: {}'.format(field[1:], repr(value)) for field, value in vars(self).items()))
def __str__(self):
return self.to_str()
def __lt__(self, other):
if not isinstance(other, Version):
return False
return False
def __eq__(self, other):
return not self < other and not other < self
def __ne__(self, other):
return self < other or other < self
def __gt__(self, other):
return other < self
def __ge__(self, other):
return not self < other
def __le__(self, other):
return not other < self
$ pylint --reports=n pylint_wrong_error_loc.py
No config file found, using default configuration
************* Module version
C: 70, 4: Missing method docstring (missing-docstring)
C: 74, 4: Missing method docstring (missing-docstring)
C: 90, 4: Missing method docstring (missing-docstring)
C:102, 4: Missing method docstring (missing-docstring)
C:113, 4: Missing method docstring (missing-docstring)
C:121, 4: Missing method docstring (missing-docstring)
C:125, 4: Missing method docstring (missing-docstring)
C:137, 4: Missing method docstring (missing-docstring)
C:172, 4: Missing method docstring (missing-docstring)
C:178, 4: Missing method docstring (missing-docstring)
C:181, 4: Missing method docstring (missing-docstring)
C:184, 4: Missing method docstring (missing-docstring)
C:187, 4: Missing method docstring (missing-docstring)
C:201, 4: Missing method docstring (missing-docstring)
C:204, 4: Missing method docstring (missing-docstring)
C:207, 4: Missing method docstring (missing-docstring)
C:210, 4: Missing method docstring (missing-docstring)
C:213, 4: Missing method docstring (missing-docstring)
R: 34,31: Too many public methods (25/20) (too-many-public-methods)
------------------------------------------------------------------
Your code has been rated at 8.68/10 (previous run: 8.68/10, +0.00)
$ pylint --reports=n version.py
No config file found, using default configuration
************* Module version
C: 70, 4: Missing method docstring (missing-docstring)
C: 74, 4: Missing method docstring (missing-docstring)
C: 90, 4: Missing method docstring (missing-docstring)
C:102, 4: Missing method docstring (missing-docstring)
C:113, 4: Missing method docstring (missing-docstring)
C:121, 4: Missing method docstring (missing-docstring)
C:125, 4: Missing method docstring (missing-docstring)
C:137, 4: Missing method docstring (missing-docstring)
C:172, 4: Missing method docstring (missing-docstring)
C:178, 4: Missing method docstring (missing-docstring)
C:181, 4: Missing method docstring (missing-docstring)
C:184, 4: Missing method docstring (missing-docstring)
C:187, 4: Missing method docstring (missing-docstring)
C:201, 4: Missing method docstring (missing-docstring)
C:204, 4: Missing method docstring (missing-docstring)
C:207, 4: Missing method docstring (missing-docstring)
C:210, 4: Missing method docstring (missing-docstring)
C:213, 4: Missing method docstring (missing-docstring)
R: 34, 0: Too many public methods (25/20) (too-many-public-methods)
------------------------------------------------------------------
Your code has been rated at 8.66/10 (previous run: 8.66/10, +0.00)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment