Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-bpython for openSUSE:Factory checked in at 2023-01-24 19:43:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-bpython (Old) and /work/SRC/openSUSE:Factory/.python-bpython.new.32243 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-bpython" Tue Jan 24 19:43:14 2023 rev:14 rq:1060526 version:0.24 Changes: -------- --- /work/SRC/openSUSE:Factory/python-bpython/python-bpython.changes 2022-11-03 19:15:41.404538703 +0100 +++ /work/SRC/openSUSE:Factory/.python-bpython.new.32243/python-bpython.changes 2023-01-24 20:30:57.799940331 +0100 @@ -1,0 +2,9 @@ +Mon Jan 23 14:39:42 UTC 2023 - Markéta Machová <mmach...@suse.com> + +- Update to version 0.24 + * Support for Python 3.11 has been added. + * wheel is no required as part of pyproject.toml's build dependencies + * Improve inspection of builtin functions. + * Add more keywords to trigger auto-deindent. + +------------------------------------------------------------------- Old: ---- bpython-0.23.tar.gz New: ---- bpython-0.24.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-bpython.spec ++++++ --- /var/tmp/diff_new_pack.gNy0Mb/_old 2023-01-24 20:30:58.375943380 +0100 +++ /var/tmp/diff_new_pack.gNy0Mb/_new 2023-01-24 20:30:58.387943443 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-bpython # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,7 +20,7 @@ %define skip_python36 1 %bcond_without test Name: python-bpython -Version: 0.23 +Version: 0.24 Release: 0 Summary: Fancy Interface to the Python Interpreter License: MIT ++++++ bpython-0.23.tar.gz -> bpython-0.24.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/.pycheckrc new/bpython-0.24/.pycheckrc --- old/bpython-0.23/.pycheckrc 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/.pycheckrc 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -blacklist = ['pyparsing', 'code', 'pygments/lexer'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/CHANGELOG.rst new/bpython-0.24/CHANGELOG.rst --- old/bpython-0.23/CHANGELOG.rst 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/CHANGELOG.rst 2023-01-18 13:48:28.000000000 +0100 @@ -1,6 +1,29 @@ Changelog ========= +0.24 +---- + +General information: + +* This release is focused on Python 3.11 support. + +New features: + +* #980: Add more keywords to trigger auto-deindent. + Thanks to Eric Burgess + +Fixes: + +* Improve inspection of builtin functions. + +Changes to dependencies: + +* wheel is no required as part of pyproject.toml's build dependencies + +Support for Python 3.11 has been added. + + 0.23 ---- @@ -22,7 +45,7 @@ * #955: Handle optional `readline` parameters in `stdin` emulation Thanks to thevibingcat * #959: Fix handling of `__name__` -* #966: Fix function signature completion for `classmethod`s +* #966: Fix function signature completion for `classmethod` Changes to dependencies: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/PKG-INFO new/bpython-0.24/PKG-INFO --- old/bpython-0.23/PKG-INFO 2022-08-30 09:54:36.195547800 +0200 +++ new/bpython-0.24/PKG-INFO 2023-01-18 13:49:30.150035000 +0100 @@ -1,14 +1,12 @@ Metadata-Version: 2.1 Name: bpython -Version: 0.23 -Summary: UNKNOWN +Version: 0.24 Home-page: https://www.bpython-interpreter.org/ Author: Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. -Author-email: robertanthonyfarr...@gmail.com +Author-email: bpyt...@googlegroups.com License: MIT Project-URL: GitHub, https://github.com/bpython/bpython Project-URL: Documentation, https://doc.bpython-interpreter.org -Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Requires-Python: >=3.7 Provides-Extra: clipboard @@ -212,5 +210,3 @@ .. _Curses: http://www.lfd.uci.edu/~gohlke/pythonlibs/ .. _pyreadline: http://pypi.python.org/pypi/pyreadline/ .. _known issues and FAQ: http://bpython-interpreter.org/known-issues-and-faq.html - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/__init__.py new/bpython-0.24/bpython/__init__.py --- old/bpython-0.23/bpython/__init__.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/__init__.py 2023-01-18 13:48:13.000000000 +0100 @@ -30,7 +30,7 @@ __author__ = ( "Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al." ) -__copyright__ = f"(C) 2008-2020 {__author__}" +__copyright__ = f"(C) 2008-2023 {__author__}" __license__ = "MIT" __version__ = version package_dir = os.path.abspath(os.path.dirname(__file__)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/_version.py new/bpython-0.24/bpython/_version.py --- old/bpython-0.23/bpython/_version.py 2022-08-30 09:54:36.000000000 +0200 +++ new/bpython-0.24/bpython/_version.py 2023-01-18 13:49:29.000000000 +0100 @@ -1,2 +1,2 @@ # Auto-generated file, do not edit! -__version__ = "0.23" +__version__ = "0.24" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/args.py new/bpython-0.24/bpython/args.py --- old/bpython-0.23/bpython/args.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/args.py 2023-01-18 13:48:28.000000000 +0100 @@ -41,6 +41,7 @@ import pygments import requests import sys +import xdg from pathlib import Path from . import __version__, __copyright__ @@ -206,11 +207,34 @@ logger.info("Starting bpython %s", __version__) logger.info("Python %s: %s", sys.executable, sys.version_info) + # versions of required dependencies logger.info("curtsies: %s", curtsies.__version__) logger.info("cwcwidth: %s", cwcwidth.__version__) logger.info("greenlet: %s", greenlet.__version__) logger.info("pygments: %s", pygments.__version__) # type: ignore + logger.info("pyxdg: %s", xdg.__version__) # type: ignore logger.info("requests: %s", requests.__version__) + + # versions of optional dependencies + try: + import pyperclip + + logger.info("pyperclip: %s", pyperclip.__version__) # type: ignore + except ImportError: + logger.info("pyperclip: not available") + try: + import jedi + + logger.info("jedi: %s", jedi.__version__) + except ImportError: + logger.info("jedi: not available") + try: + import watchdog + + logger.info("watchdog: available") + except ImportError: + logger.info("watchdog: not available") + logger.info("environment:") for key, value in sorted(os.environ.items()): if key.startswith("LC") or key.startswith("LANG") or key == "TERM": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/autocomplete.py new/bpython-0.24/bpython/autocomplete.py --- old/bpython-0.23/bpython/autocomplete.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/autocomplete.py 2023-01-18 13:48:13.000000000 +0100 @@ -555,11 +555,10 @@ if r is None: return None - matches = set() n = len(r.word) - for word in KEYWORDS: - if self.method_match(word, n, r.word): - matches.add(word) + matches = { + word for word in KEYWORDS if self.method_match(word, n, r.word) + } for nspace in (builtins.__dict__, locals_): for word, val in nspace.items(): # if identifier isn't ascii, don't complete (syntax error) @@ -598,7 +597,7 @@ if isinstance(name, str) and name.startswith(r.word) } matches.update( - name + "=" + f"{name}=" for name in funcprops.argspec.kwonly if name.startswith(r.word) ) @@ -652,7 +651,7 @@ else: - class JediCompletion(BaseCompletionType): + class MultilineJediCompletion(BaseCompletionType): # type: ignore [no-redef] _orig_start: Optional[int] def matches( @@ -660,19 +659,28 @@ cursor_offset: int, line: str, *, + current_block: Optional[str] = None, history: Optional[List[str]] = None, **kwargs: Any, ) -> Optional[Set[str]]: - if history is None: - return None - if not lineparts.current_word(cursor_offset, line): + if ( + current_block is None + or history is None + or "\n" not in current_block + or not lineparts.current_word(cursor_offset, line) + ): return None + assert cursor_offset <= len(line), "{!r} {!r}".format( + cursor_offset, + line, + ) + combined_history = "\n".join(itertools.chain(history, (line,))) try: script = jedi.Script(combined_history, path="fake.py") completions = script.complete( - len(combined_history.splitlines()), cursor_offset + combined_history.count("\n") + 1, cursor_offset ) except (jedi.NotFoundError, IndexError, KeyError): # IndexError for #483 @@ -688,8 +696,6 @@ return None assert isinstance(self._orig_start, int) - first_letter = line[self._orig_start : self._orig_start + 1] - matches = [c.name for c in completions] if any( not m.lower().startswith(matches[0][0].lower()) for m in matches @@ -699,35 +705,15 @@ return None else: # case-sensitive matches only + first_letter = line[self._orig_start] return {m for m in matches if m.startswith(first_letter)} def locate(self, cursor_offset: int, line: str) -> LinePart: - assert isinstance(self._orig_start, int) + assert self._orig_start is not None start = self._orig_start end = cursor_offset return LinePart(start, end, line[start:end]) - class MultilineJediCompletion(JediCompletion): # type: ignore [no-redef] - def matches( - self, - cursor_offset: int, - line: str, - *, - current_block: Optional[str] = None, - history: Optional[List[str]] = None, - **kwargs: Any, - ) -> Optional[Set[str]]: - if current_block is None or history is None: - return None - if "\n" not in current_block: - return None - - assert cursor_offset <= len(line), "{!r} {!r}".format( - cursor_offset, - line, - ) - return super().matches(cursor_offset, line, history=history) - def get_completer( completers: Sequence[BaseCompletionType], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/cli.py new/bpython-0.24/bpython/cli.py --- old/bpython-0.23/bpython/cli.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/cli.py 2023-01-18 13:48:28.000000000 +0100 @@ -1299,7 +1299,7 @@ arg_pos: Union[str, int, None], topline: Optional[inspection.FuncProps] = None, formatter: Optional[Callable] = None, - current_item: Union[str, Literal[False]] = None, + current_item: Optional[str] = None, ) -> None: v_items: Collection shared = ShowListState() @@ -1315,7 +1315,7 @@ if items and formatter: items = [formatter(x) for x in items] - if current_item: + if current_item is not None: current_item = formatter(current_item) if topline: @@ -1492,8 +1492,10 @@ # 4. swap current word for a match list item elif self.matches_iter.matches: - current_match: Union[str, Literal[False]] = ( - back and self.matches_iter.previous() or next(self.matches_iter) + current_match = ( + self.matches_iter.previous() + if back + else next(self.matches_iter) ) try: f = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/curtsies.py new/bpython-0.24/bpython/curtsies.py --- old/bpython-0.23/bpython/curtsies.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/curtsies.py 2023-01-18 13:48:28.000000000 +0100 @@ -106,7 +106,7 @@ return self._schedule_refresh_callback(when) def _request_reload(self, files_modified: Sequence[str]) -> None: - return self._request_reload_callback(files_modified) + return self._request_reload_callback(files_modified=files_modified) def interrupting_refresh(self) -> None: return self._interrupting_refresh_callback() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/curtsiesfrontend/repl.py new/bpython-0.24/bpython/curtsiesfrontend/repl.py --- old/bpython-0.23/bpython/curtsiesfrontend/repl.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/curtsiesfrontend/repl.py 2023-01-18 13:48:28.000000000 +0100 @@ -269,54 +269,39 @@ def __getattr__(self, name): if name == "create_module" and hasattr(self.loader, name): return self._create_module - if name == "load_module" and hasattr(self.loader, name): - return self._load_module return getattr(self.loader, name) def _create_module(self, spec): - spec = self.loader.create_module(spec) + module_object = self.loader.create_module(spec) if ( getattr(spec, "origin", None) is not None and spec.origin != "builtin" ): self.watcher.track_module(spec.origin) - return spec - - def _load_module(self, name): - module = self.loader.load_module(name) - if hasattr(module, "__file__"): - self.watcher.track_module(module.__file__) - return module + return module_object class ImportFinder: - """Wrapper for finders in sys.meta_path to replace wrap all loaders with ImportLoader.""" + """Wrapper for finders in sys.meta_path to wrap all loaders with ImportLoader.""" - def __init__(self, finder, watcher): + def __init__(self, watcher, finder): self.watcher = watcher self.finder = finder def __getattr__(self, name): if name == "find_spec" and hasattr(self.finder, name): return self._find_spec - if name == "find_module" and hasattr(self.finder, name): - return self._find_module return getattr(self.finder, name) def _find_spec(self, fullname, path, target=None): # Attempt to find the spec spec = self.finder.find_spec(fullname, path, target) if spec is not None: - if getattr(spec, "__loader__", None) is not None: + if getattr(spec, "loader", None) is not None: # Patch the loader to enable reloading - spec.__loader__ = ImportLoader(self.watcher, spec.__loader__) + spec.loader = ImportLoader(self.watcher, spec.loader) return spec - def _find_module(self, fullname, path=None): - loader = self.finder.find_module(fullname, path) - if loader is not None: - return ImportLoader(self.watcher, loader) - def _process_ps(ps, default_ps: str): """Replace ps1/ps2 with the default if the user specified value contains control characters.""" @@ -607,14 +592,7 @@ if self.watcher: meta_path = [] for finder in sys.meta_path: - # All elements get wrapped in ImportFinder instances execepted for instances of - # _SixMetaPathImporter (from six). When importing six, it will check if the importer - # is already part of sys.meta_path and will remove instances. We do not want to - # break this feature (see also #874). - if type(finder).__name__ == "_SixMetaPathImporter": - meta_path.append(finder) - else: - meta_path.append(ImportFinder(finder, self.watcher)) + meta_path.append(ImportFinder(self.watcher, finder)) sys.meta_path = meta_path sitefix.monkeypatch_quit() @@ -1274,7 +1252,9 @@ elif ( line and ":" not in line - and line.strip().startswith(("return", "pass", "raise", "yield")) + and line.strip().startswith( + ("return", "pass", "...", "raise", "yield", "break", "continue") + ) ): indent = max(0, indent - self.config.tab_length) logger.debug("indent we found was %s", indent) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/history.py new/bpython-0.24/bpython/history.py --- old/bpython-0.23/bpython/history.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/history.py 2023-01-18 13:48:13.000000000 +0100 @@ -25,7 +25,7 @@ from pathlib import Path import stat from itertools import islice, chain -from typing import Iterable, Optional, List, TextIO, Union +from typing import Iterable, Optional, List, TextIO from .translations import _ from .filelock import FileLock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/importcompletion.py new/bpython-0.24/bpython/importcompletion.py --- old/bpython-0.23/bpython/importcompletion.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/importcompletion.py 2023-01-18 13:48:28.000000000 +0100 @@ -25,8 +25,9 @@ import importlib.machinery import sys import warnings +from dataclasses import dataclass from pathlib import Path -from typing import Optional, Set, Generator, Tuple, Sequence, Iterable, Union +from typing import Optional, Set, Generator, Sequence, Iterable, Union from .line import ( current_word, @@ -47,6 +48,16 @@ ), ) +_LOADED_INODE_DATACLASS_ARGS = {"frozen": True} +if sys.version_info[:2] >= (3, 10): + _LOADED_INODE_DATACLASS_ARGS["slots"] = True + + +@dataclass(**_LOADED_INODE_DATACLASS_ARGS) +class _LoadedInode: + dev: int + inode: int + class ModuleGatherer: def __init__( @@ -60,7 +71,7 @@ # Cached list of all known modules self.modules: Set[str] = set() # Set of (st_dev, st_ino) to compare against so that paths are not repeated - self.paths: Set[Tuple[int, int]] = set() + self.paths: Set[_LoadedInode] = set() # Patterns to skip self.skiplist: Sequence[str] = ( skiplist if skiplist is not None else tuple() @@ -72,7 +83,7 @@ paths = sys.path self.find_iterator = self.find_all_modules( - (Path(p).resolve() if p else Path.cwd() for p in paths) + Path(p).resolve() if p else Path.cwd() for p in paths ) def module_matches(self, cw: str, prefix: str = "") -> Set[str]: @@ -109,7 +120,7 @@ matches = { name for name in dir(module) if name.startswith(name_after_dot) } - module_part, _, _ = cw.rpartition(".") + module_part = cw.rpartition(".")[0] if module_part: matches = {f"{module_part}.{m}" for m in matches} @@ -155,9 +166,7 @@ else: return None - def find_modules( - self, path: Path - ) -> Generator[Union[str, None], None, None]: + def find_modules(self, path: Path) -> Generator[Optional[str], None, None]: """Find all modules (and packages) for a given directory.""" if not path.is_dir(): # Perhaps a zip file @@ -177,7 +186,10 @@ finder = importlib.machinery.FileFinder(str(path), *LOADERS) # type: ignore for p in children: - if any(fnmatch.fnmatch(p.name, entry) for entry in self.skiplist): + if p.name.startswith(".") or p.name == "__pycache__": + # Impossible to import from names starting with . and we can skip __pycache__ + continue + elif any(fnmatch.fnmatch(p.name, entry) for entry in self.skiplist): # Path is on skiplist continue elif not any(p.name.endswith(suffix) for suffix in SUFFIXES): @@ -196,36 +208,35 @@ if name == "badsyntax_pep3120": # Workaround for issue #166 continue + + package_pathname = None try: - is_package = False with warnings.catch_warnings(): warnings.simplefilter("ignore", ImportWarning) spec = finder.find_spec(name) if spec is None: continue if spec.submodule_search_locations is not None: - pathname = spec.submodule_search_locations[0] - is_package = True - except (ImportError, OSError, SyntaxError): - continue - except UnicodeEncodeError: - # Happens with Python 3 when there is a filename in some invalid encoding + package_pathname = spec.submodule_search_locations[0] + except (ImportError, OSError, SyntaxError, UnicodeEncodeError): + # UnicodeEncodeError happens with Python 3 when there is a filename in some invalid encoding continue - else: - if is_package: - path_real = Path(pathname).resolve() - try: - stat = path_real.stat() - except OSError: - continue - if (stat.st_dev, stat.st_ino) not in self.paths: - self.paths.add((stat.st_dev, stat.st_ino)) - for subname in self.find_modules(path_real): - if subname is None: - yield None # take a break to avoid unresponsiveness - elif subname != "__init__": - yield f"{name}.{subname}" - yield name + + if package_pathname is not None: + path_real = Path(package_pathname).resolve() + try: + stat = path_real.stat() + except OSError: + continue + loaded_inode = _LoadedInode(stat.st_dev, stat.st_ino) + if loaded_inode not in self.paths: + self.paths.add(loaded_inode) + for subname in self.find_modules(path_real): + if subname is None: + yield None # take a break to avoid unresponsiveness + elif subname != "__init__": + yield f"{name}.{subname}" + yield name yield None # take a break to avoid unresponsiveness def find_all_modules( @@ -240,9 +251,9 @@ self.modules.add(module) yield - def find_coroutine(self) -> Optional[bool]: + def find_coroutine(self) -> bool: if self.fully_loaded: - return None + return False try: next(self.find_iterator) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/inspection.py new/bpython-0.24/bpython/inspection.py --- old/bpython-0.23/bpython/inspection.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/inspection.py 2023-01-18 13:48:28.000000000 +0100 @@ -36,14 +36,30 @@ from .lazyre import LazyReCompile +class _Repr: + """ + Helper for `ArgSpec`: Returns the given value in `__repr__()`. + """ + + __slots__ = ("value",) + + def __init__(self, value: str) -> None: + self.value = value + + def __repr__(self) -> str: + return self.value + + __str__ = __repr__ + + @dataclass class ArgSpec: args: List[str] varargs: Optional[str] varkwargs: Optional[str] - defaults: Optional[List[Any]] + defaults: Optional[List[_Repr]] kwonly: List[str] - kwonly_defaults: Optional[Dict[str, Any]] + kwonly_defaults: Optional[Dict[str, _Repr]] annotations: Optional[Dict[str, Any]] @@ -110,20 +126,6 @@ return False -class _Repr: - """ - Helper for `fixlongargs()`: Returns the given value in `__repr__()`. - """ - - def __init__(self, value: str) -> None: - self.value = value - - def __repr__(self) -> str: - return self.value - - __str__ = __repr__ - - def parsekeywordpairs(signature: str) -> Dict[str, str]: preamble = True stack = [] @@ -142,19 +144,19 @@ parendepth += 1 elif value in ")}]": parendepth -= 1 - elif value == ":" and parendepth == -1: - # End of signature reached - break - elif value == ":" and parendepth == 0: - # Start of type annotation - annotation = True - - if (value == "," and parendepth == 0) or ( - value == ")" and parendepth == -1 - ): + elif value == ":": + if parendepth == -1: + # End of signature reached + break + elif parendepth == 0: + # Start of type annotation + annotation = True + + if (value, parendepth) in ((",", 0), (")", -1)): + # End of current argument stack.append(substack) substack = [] - # If type annotation didn't end before, ti does now. + # If type annotation didn't end before, it does now. annotation = False continue elif token is Token.Operator and value == "=" and parendepth == 0: @@ -167,31 +169,45 @@ return {item[0]: "".join(item[2:]) for item in stack if len(item) >= 3} -def _fixlongargs(f: Callable, argspec: ArgSpec) -> ArgSpec: +def _fix_default_values(f: Callable, argspec: ArgSpec) -> ArgSpec: """Functions taking default arguments that are references to other objects - whose str() is too big will cause breakage, so we swap out the object - itself with the name it was referenced with in the source by parsing the - source itself !""" - if argspec.defaults is None: + will cause breakage, so we swap out the object itself with the name it was + referenced with in the source by parsing the source itself!""" + + if argspec.defaults is None and argspec.kwonly_defaults is None: # No keyword args, no need to do anything return argspec - values = list(argspec.defaults) - if not values: - return argspec - keys = argspec.args[-len(values) :] + try: - src = inspect.getsourcelines(f) + src, _ = inspect.getsourcelines(f) except (OSError, IndexError): # IndexError is raised in inspect.findsource(), can happen in # some situations. See issue #94. return argspec - kwparsed = parsekeywordpairs("".join(src[0])) + except TypeError: + # No source code is available, so replace the default values with what we have. + if argspec.defaults is not None: + argspec.defaults = [_Repr(str(value)) for value in argspec.defaults] + if argspec.kwonly_defaults is not None: + argspec.kwonly_defaults = { + key: _Repr(str(value)) + for key, value in argspec.kwonly_defaults.items() + } + return argspec - for i, (key, value) in enumerate(zip(keys, values)): - if len(repr(value)) != len(kwparsed[key]): + kwparsed = parsekeywordpairs("".join(src)) + + if argspec.defaults is not None: + values = list(argspec.defaults) + keys = argspec.args[-len(values) :] + for i, key in enumerate(keys): values[i] = _Repr(kwparsed[key]) - argspec.defaults = values + argspec.defaults = values + if argspec.kwonly_defaults is not None: + for key in argspec.kwonly_defaults.keys(): + argspec.kwonly_defaults[key] = _Repr(kwparsed[key]) + return argspec @@ -232,11 +248,11 @@ if varargs is not None: kwonly_args.append(arg) if default: - kwonly_defaults[arg] = default + kwonly_defaults[arg] = _Repr(default) else: args.append(arg) if default: - defaults.append(default) + defaults.append(_Repr(default)) return ArgSpec( args, varargs, varkwargs, defaults, kwonly_args, kwonly_defaults, None @@ -265,7 +281,9 @@ return None try: argspec = _get_argspec_from_signature(f) - fprops = FuncProps(func, _fixlongargs(f, argspec), is_bound_method) + fprops = FuncProps( + func, _fix_default_values(f, argspec), is_bound_method + ) except (TypeError, KeyError, ValueError): argspec_pydoc = _getpydocspec(f) if argspec_pydoc is None: @@ -293,12 +311,15 @@ """ args = [] - varargs = varkwargs = None + varargs = None + varkwargs = None defaults = [] kwonly = [] kwonly_defaults = {} annotations = {} + # We use signature here instead of getfullargspec as the latter also returns + # self and cls (for class methods). signature = inspect.signature(f) for parameter in signature.parameters.values(): if parameter.annotation is not parameter.empty: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/pager.py new/bpython-0.24/bpython/pager.py --- old/bpython-0.23/bpython/pager.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/pager.py 2023-01-18 13:48:13.000000000 +0100 @@ -63,7 +63,6 @@ # pager command not found, fall back to internal pager page_internal(data) return - except OSError as e: if e.errno != errno.EPIPE: raise while True: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/patch_linecache.py new/bpython-0.24/bpython/patch_linecache.py --- old/bpython-0.23/bpython/patch_linecache.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/patch_linecache.py 2023-01-18 13:48:13.000000000 +0100 @@ -1,21 +1,24 @@ import linecache -from typing import Any, List, Tuple +from typing import Any, List, Tuple, Optional class BPythonLinecache(dict): """Replaces the cache dict in the standard-library linecache module, to also remember (in an unerasable way) bpython console input.""" - def __init__(self, *args, **kwargs) -> None: + def __init__( + self, + bpython_history: Optional[ + List[Tuple[int, None, List[str], str]] + ] = None, + *args, + **kwargs, + ) -> None: super().__init__(*args, **kwargs) - self.bpython_history: List[Tuple[int, None, List[str], str]] = [] + self.bpython_history = bpython_history or [] def is_bpython_filename(self, fname: Any) -> bool: - if isinstance(fname, str): - return fname.startswith("<bpython-input-") - else: - # In case the key isn't a string - return False + return isinstance(fname, str) and fname.startswith("<bpython-input-") def get_bpython_history(self, key: str) -> Tuple[int, None, List[str], str]: """Given a filename provided by remember_bpython_input, @@ -58,14 +61,13 @@ if isinstance(linecache.cache, BPythonLinecache): bpython_history = linecache.cache.bpython_history else: - bpython_history = [] - linecache.cache = BPythonLinecache() - linecache.cache.bpython_history = bpython_history + bpython_history = None + linecache.cache = BPythonLinecache(bpython_history) -# Monkey-patch the linecache module so that we're able +# Monkey-patch the linecache module so that we are able # to hold our command history there and have it persist -linecache.cache = BPythonLinecache(linecache.cache) # type: ignore +linecache.cache = BPythonLinecache(None, linecache.cache) # type: ignore linecache.clearcache = _bpython_clear_linecache diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/repl.py new/bpython-0.24/bpython/repl.py --- old/bpython-0.23/bpython/repl.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/repl.py 2023-01-18 13:48:28.000000000 +0100 @@ -1255,7 +1255,9 @@ if line.rstrip().endswith(":"): indentation += 1 elif indentation >= 1: - if line.lstrip().startswith(("return", "pass", "raise", "yield")): + if line.lstrip().startswith( + ("return", "pass", "...", "raise", "yield", "break", "continue") + ): indentation -= 1 return indentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/test/test_curtsies_painting.py new/bpython-0.24/bpython/test/test_curtsies_painting.py --- old/bpython-0.23/bpython/test/test_curtsies_painting.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/test/test_curtsies_painting.py 2023-01-18 13:48:13.000000000 +0100 @@ -13,7 +13,7 @@ ) from curtsies.fmtfuncs import cyan, bold, green, yellow, on_magenta, red from curtsies.window import CursorAwareWindow -from unittest import mock +from unittest import mock, skipIf from bpython.curtsiesfrontend.events import RefreshRequestEvent from bpython import config, inspection @@ -311,6 +311,10 @@ cursor_pos = self.repl.paint()[1] self.assertEqual(cursor_pos, (1, 4)) + @skipIf( + sys.version_info[:2] >= (3, 11) and sys.version_info[:3] < (3, 11, 1), + "https://github.com/python/cpython/issues/98744", + ) def test_display_of_padding_chars(self): self.repl.width = 11 [self.repl.add_normal_character(c) for c in "ï½ï½ï½ï½ï½"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/test/test_inspection.py new/bpython-0.24/bpython/test/test_inspection.py --- old/bpython-0.23/bpython/test/test_inspection.py 2022-08-30 09:53:09.000000000 +0200 +++ new/bpython-0.24/bpython/test/test_inspection.py 2023-01-18 13:48:13.000000000 +0100 @@ -11,6 +11,7 @@ from bpython.test.fodder import encoding_utf8 pypy = "PyPy" in sys.version +_is_py311 = sys.version_info[:2] >= (3, 11) try: import numpy @@ -53,23 +54,17 @@ def fails(spam=["-a", "-b"]): pass - default_arg_repr = "['-a', '-b']" - self.assertEqual( - str(["-a", "-b"]), - default_arg_repr, - "This test is broken (repr does not match), fix me.", - ) - argspec = inspection.getfuncprops("fails", fails) + self.assertIsNotNone(argspec) defaults = argspec.argspec.defaults - self.assertEqual(str(defaults[0]), default_arg_repr) + self.assertEqual(str(defaults[0]), '["-a", "-b"]') def test_pasekeywordpairs_string(self): def spam(eggs="foo, bar"): pass defaults = inspection.getfuncprops("spam", spam).argspec.defaults - self.assertEqual(repr(defaults[0]), "'foo, bar'") + self.assertEqual(repr(defaults[0]), '"foo, bar"') def test_parsekeywordpairs_multiple_keywords(self): def spam(eggs=23, foobar="yay"): @@ -77,14 +72,14 @@ defaults = inspection.getfuncprops("spam", spam).argspec.defaults self.assertEqual(repr(defaults[0]), "23") - self.assertEqual(repr(defaults[1]), "'yay'") + self.assertEqual(repr(defaults[1]), '"yay"') def test_pasekeywordpairs_annotation(self): def spam(eggs: str = "foo, bar"): pass defaults = inspection.getfuncprops("spam", spam).argspec.defaults - self.assertEqual(repr(defaults[0]), "'foo, bar'") + self.assertEqual(repr(defaults[0]), '"foo, bar"') def test_get_encoding_ascii(self): self.assertEqual(inspection.get_encoding(encoding_ascii), "ascii") @@ -134,8 +129,15 @@ self.assertIn("file", props.argspec.kwonly) self.assertIn("flush", props.argspec.kwonly) self.assertIn("sep", props.argspec.kwonly) - self.assertEqual(props.argspec.kwonly_defaults["file"], "sys.stdout") - self.assertEqual(props.argspec.kwonly_defaults["flush"], "False") + if _is_py311: + self.assertEqual( + repr(props.argspec.kwonly_defaults["file"]), "None" + ) + else: + self.assertEqual( + repr(props.argspec.kwonly_defaults["file"]), "sys.stdout" + ) + self.assertEqual(repr(props.argspec.kwonly_defaults["flush"]), "False") @unittest.skipUnless( numpy is not None and numpy.__version__ >= "1.18", @@ -173,12 +175,12 @@ props = inspection.getfuncprops("fun", fun) self.assertEqual(props.func, "fun") self.assertEqual(props.argspec.args, ["number", "lst"]) - self.assertEqual(props.argspec.defaults[0], []) + self.assertEqual(repr(props.argspec.defaults[0]), "[]") props = inspection.getfuncprops("fun_annotations", fun_annotations) self.assertEqual(props.func, "fun_annotations") self.assertEqual(props.argspec.args, ["number", "lst"]) - self.assertEqual(props.argspec.defaults[0], []) + self.assertEqual(repr(props.argspec.defaults[0]), "[]") def test_issue_966_class_method(self): class Issue966(Sequence): @@ -215,7 +217,7 @@ ) self.assertEqual(props.func, "cmethod") self.assertEqual(props.argspec.args, ["number", "lst"]) - self.assertEqual(props.argspec.defaults[0], []) + self.assertEqual(repr(props.argspec.defaults[0]), "[]") def test_issue_966_static_method(self): class Issue966(Sequence): @@ -252,7 +254,7 @@ ) self.assertEqual(props.func, "cmethod") self.assertEqual(props.argspec.args, ["number", "lst"]) - self.assertEqual(props.argspec.defaults[0], []) + self.assertEqual(repr(props.argspec.defaults[0]), "[]") class A: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/test/test_interpreter.py new/bpython-0.24/bpython/test/test_interpreter.py --- old/bpython-0.23/bpython/test/test_interpreter.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/test/test_interpreter.py 2023-01-18 13:48:28.000000000 +0100 @@ -112,19 +112,35 @@ global_not_found = "name 'gfunc' is not defined" - expected = ( - "Traceback (most recent call last):\n File " - + green('"<input>"') - + ", line " - + bold(magenta("1")) - + ", in " - + cyan("<module>") - + "\n gfunc()\n" - + bold(red("NameError")) - + ": " - + cyan(global_not_found) - + "\n" - ) + if (3, 11) <= sys.version_info[:2]: + expected = ( + "Traceback (most recent call last):\n File " + + green('"<input>"') + + ", line " + + bold(magenta("1")) + + ", in " + + cyan("<module>") + + "\n gfunc()" + + "\n ^^^^^\n" + + bold(red("NameError")) + + ": " + + cyan(global_not_found) + + "\n" + ) + else: + expected = ( + "Traceback (most recent call last):\n File " + + green('"<input>"') + + ", line " + + bold(magenta("1")) + + ", in " + + cyan("<module>") + + "\n gfunc()\n" + + bold(red("NameError")) + + ": " + + cyan(global_not_found) + + "\n" + ) self.assertMultiLineEqual(str(plain("").join(a)), str(expected)) self.assertEqual(plain("").join(a), expected) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython/translations/__init__.py new/bpython-0.24/bpython/translations/__init__.py --- old/bpython-0.23/bpython/translations/__init__.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/bpython/translations/__init__.py 2023-01-18 13:48:13.000000000 +0100 @@ -2,7 +2,7 @@ import locale import os.path import sys -from typing import cast, List +from typing import Optional, cast, List from .. import package_dir @@ -17,7 +17,9 @@ return translator.ngettext(singular, plural, n) -def init(locale_dir: str = None, languages: List[str] = None) -> None: +def init( + locale_dir: Optional[str] = None, languages: Optional[List[str]] = None +) -> None: try: locale.setlocale(locale.LC_ALL, "") except locale.Error: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython.egg-info/PKG-INFO new/bpython-0.24/bpython.egg-info/PKG-INFO --- old/bpython-0.23/bpython.egg-info/PKG-INFO 2022-08-30 09:54:36.000000000 +0200 +++ new/bpython-0.24/bpython.egg-info/PKG-INFO 2023-01-18 13:49:29.000000000 +0100 @@ -1,14 +1,12 @@ Metadata-Version: 2.1 Name: bpython -Version: 0.23 -Summary: UNKNOWN +Version: 0.24 Home-page: https://www.bpython-interpreter.org/ Author: Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. -Author-email: robertanthonyfarr...@gmail.com +Author-email: bpyt...@googlegroups.com License: MIT Project-URL: GitHub, https://github.com/bpython/bpython Project-URL: Documentation, https://doc.bpython-interpreter.org -Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Requires-Python: >=3.7 Provides-Extra: clipboard @@ -212,5 +210,3 @@ .. _Curses: http://www.lfd.uci.edu/~gohlke/pythonlibs/ .. _pyreadline: http://pypi.python.org/pypi/pyreadline/ .. _known issues and FAQ: http://bpython-interpreter.org/known-issues-and-faq.html - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython.egg-info/SOURCES.txt new/bpython-0.24/bpython.egg-info/SOURCES.txt --- old/bpython-0.23/bpython.egg-info/SOURCES.txt 2022-08-30 09:54:36.000000000 +0200 +++ new/bpython-0.24/bpython.egg-info/SOURCES.txt 2023-01-18 13:49:30.000000000 +0100 @@ -1,4 +1,3 @@ -.pycheckrc AUTHORS.rst CHANGELOG.rst LICENSE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/bpython.egg-info/entry_points.txt new/bpython-0.24/bpython.egg-info/entry_points.txt --- old/bpython-0.23/bpython.egg-info/entry_points.txt 2022-08-30 09:54:36.000000000 +0200 +++ new/bpython-0.24/bpython.egg-info/entry_points.txt 2023-01-18 13:49:29.000000000 +0100 @@ -3,4 +3,3 @@ bpython = bpython.curtsies:main bpython-curses = bpython.cli:main bpython-urwid = bpython.urwid:main [urwid] - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/pyproject.toml new/bpython-0.24/pyproject.toml --- old/bpython-0.23/pyproject.toml 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/pyproject.toml 2023-01-18 13:48:28.000000000 +0100 @@ -1,8 +1,8 @@ [build-system] requires = [ "setuptools >= 43", - "wheel", ] +build-backend = "setuptools.build_meta" [tool.black] line-length = 80 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/setup.cfg new/bpython-0.24/setup.cfg --- old/bpython-0.23/setup.cfg 2022-08-30 09:54:36.196548000 +0200 +++ new/bpython-0.24/setup.cfg 2023-01-18 13:49:30.150035000 +0100 @@ -2,7 +2,9 @@ name = bpython long_description = file: README.rst license = MIT -license_file = LICENSE +license_files = LICENSE +author = Bob Farrell, Andreas Stuehrk, Sebastian Ramacher, Thomas Ballinger, et al. +author_email = bpyt...@googlegroups.com url = https://www.bpython-interpreter.org/ project_urls = GitHub = https://github.com/bpython/bpython @@ -78,6 +80,9 @@ [mypy-urwid] ignore_missing_imports = True +[mypy-twisted.*] +ignore_missing_imports = True + [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bpython-0.23/setup.py new/bpython-0.24/setup.py --- old/bpython-0.23/setup.py 2022-07-15 20:13:24.000000000 +0200 +++ new/bpython-0.24/setup.py 2023-01-18 13:48:13.000000000 +0100 @@ -124,9 +124,7 @@ cmdclass = {"build": build} -from bpython import package_dir, __author__ - -translations_dir = os.path.join(package_dir, "translations") +translations_dir = os.path.join("bpython", "translations") # localization options if using_translations: @@ -179,8 +177,6 @@ setup( version=version, - author=__author__, - author_email="robertanthonyfarr...@gmail.com", data_files=data_files, package_data={ "bpython": ["sample-config"],