diff --git a/src/basilisp/cli.py b/src/basilisp/cli.py index 833f0b90..1d7dd262 100644 --- a/src/basilisp/cli.py +++ b/src/basilisp/cli.py @@ -6,9 +6,9 @@ import sys import textwrap import types -from collections.abc import Sequence +from collections.abc import Callable, Sequence from pathlib import Path -from typing import Any, Callable, Optional, Union +from typing import Any, Union from basilisp import main as basilisp from basilisp.lang import compiler as compiler @@ -97,7 +97,7 @@ def prepend_once(path: str) -> None: prepend_once(unsafe_path) -def _to_bool(v: Optional[str]) -> Optional[bool]: +def _to_bool(v: str | None) -> bool | None: """Coerce a string argument to a boolean value, if possible.""" if v is None: return v @@ -389,8 +389,8 @@ def _add_runtime_arg_group(parser: argparse.ArgumentParser) -> None: def _subcommand( subcommand: str, *, - help: Optional[str] = None, # pylint: disable=redefined-builtin - description: Optional[str] = None, + help: str | None = None, # pylint: disable=redefined-builtin + description: str | None = None, handler: Handler, allows_extra: bool = False, ) -> Callable[ @@ -820,7 +820,7 @@ def run_script(): os.execvp("basilisp", args) # nosec B606, B607 -def invoke_cli(args: Optional[Sequence[str]] = None) -> None: +def invoke_cli(args: Sequence[str] | None = None) -> None: """Entrypoint to run the Basilisp CLI.""" parser = argparse.ArgumentParser( description="Basilisp is a Lisp dialect inspired by Clojure targeting Python 3." diff --git a/src/basilisp/contrib/pytest/testrunner.py b/src/basilisp/contrib/pytest/testrunner.py index e573f9a3..fdf44dd3 100644 --- a/src/basilisp/contrib/pytest/testrunner.py +++ b/src/basilisp/contrib/pytest/testrunner.py @@ -3,10 +3,10 @@ import os import sys import traceback -from collections.abc import Iterable, Iterator +from collections.abc import Callable, Iterable, Iterator from pathlib import Path from types import GeneratorType -from typing import Callable, Optional +from typing import Optional import pytest @@ -108,7 +108,7 @@ def __init__(self, fixtures: Iterable[FixtureFunction]): self._teardowns: Iterable[FixtureTeardown] = () @staticmethod - def _run_fixture(fixture: FixtureFunction) -> Optional[Iterator[None]]: + def _run_fixture(fixture: FixtureFunction) -> Iterator[None] | None: """Run a fixture function. If the fixture is a generator function, return the generator/coroutine. Otherwise, simply return the value from the function, if one.""" @@ -199,7 +199,7 @@ class BasilispFile(pytest.File): def __init__(self, **kwargs) -> None: super().__init__(**kwargs) - self._fixture_manager: Optional[FixtureManager] = None + self._fixture_manager: FixtureManager | None = None @staticmethod def _collected_fixtures( @@ -248,7 +248,7 @@ def _import_module(self) -> runtime.BasilispModule: modnames = _get_fully_qualified_module_names(self.path) assert modnames, "Must have at least one module name" - exc: Optional[ModuleNotFoundError] = None + exc: ModuleNotFoundError | None = None for modname in modnames: try: module = importlib.import_module(modname) @@ -360,7 +360,7 @@ def runtest(self): If any tests fail, raise an ExceptionInfo exception with the test failures. PyTest will invoke self.repr_failure to display the failures to the user.""" results: lmap.PersistentMap = self._run_test() - failures: Optional[vec.PersistentVector] = results.val_at(_FAILURES_KW) + failures: vec.PersistentVector | None = results.val_at(_FAILURES_KW) if runtime.to_seq(failures): raise TestFailuresInfo("Test failures", lmap.map(results)) @@ -391,7 +391,7 @@ def repr_failure(self, excinfo, style=None): def reportinfo(self): return self.fspath, 0, self.name - def _error_msg(self, exc: Exception, line: Optional[int] = None) -> str: + def _error_msg(self, exc: Exception, line: int | None = None) -> str: line_msg = Maybe(line).map(lambda l: f":{l}").or_else_get("") messages = [f"ERROR in ({self.name}) ({self._filename}{line_msg})", "\n\n"] messages.extend(traceback.format_exception(Exception, exc, exc.__traceback__)) diff --git a/src/basilisp/contrib/sphinx/autodoc.py b/src/basilisp/contrib/sphinx/autodoc.py index cfb4c05d..ac3acf5f 100644 --- a/src/basilisp/contrib/sphinx/autodoc.py +++ b/src/basilisp/contrib/sphinx/autodoc.py @@ -3,7 +3,7 @@ import logging import sys import types -from typing import Any, Optional, cast +from typing import Any, cast from sphinx.ext.autodoc import ( ClassDocumenter, @@ -51,7 +51,7 @@ _METHODS_KW = kw.keyword("methods") -def _get_doc(reference: IReference) -> Optional[list[list[str]]]: +def _get_doc(reference: IReference) -> list[list[str]] | None: """Return the docstring of an IReference type (e.g. Namespace or Var).""" docstring = reference.meta and reference.meta.val_at(_DOC_KW) if docstring is None: @@ -79,7 +79,7 @@ class NamespaceDocumenter(Documenter): "deprecated": bool_option, } - object: Optional[runtime.Namespace] + object: runtime.Namespace | None @classmethod def can_document_member( @@ -122,7 +122,7 @@ def import_object(self, raiseerror: bool = False) -> bool: self.module = ns.module return True - def get_doc(self) -> Optional[list[list[str]]]: + def get_doc(self) -> list[list[str]] | None: assert self.object is not None return _get_doc(self.object) @@ -155,7 +155,7 @@ def filter_members( continue if val.meta is not None: # Ignore undocumented members unless undoc_members is set - docstring: Optional[str] = val.meta.val_at(_DOC_KW) + docstring: str | None = val.meta.val_at(_DOC_KW) if docstring is None and not self.options.undoc_members: continue # Private members will be excluded unless they are requested @@ -215,7 +215,7 @@ class VarDocumenter(Documenter): "deprecated": bool_option, } - object: Optional[runtime.Var] + object: runtime.Var | None @classmethod def can_document_member( @@ -292,7 +292,7 @@ def add_directive_header(self, sig: str) -> None: if self.object.meta.val_at(_DEPRECATED_KW): self.add_line(" :deprecated:", sourcename) - def get_doc(self) -> Optional[list[list[str]]]: + def get_doc(self) -> list[list[str]] | None: assert self.object is not None return _get_doc(self.object) diff --git a/src/basilisp/contrib/sphinx/domain.py b/src/basilisp/contrib/sphinx/domain.py index 9434ece3..8eed7c62 100644 --- a/src/basilisp/contrib/sphinx/domain.py +++ b/src/basilisp/contrib/sphinx/domain.py @@ -1,7 +1,7 @@ import logging from collections import defaultdict from collections.abc import Iterable -from typing import Any, NamedTuple, Optional, Union, cast +from typing import Any, NamedTuple, cast from docutils import nodes from docutils.nodes import Element, Node @@ -316,7 +316,7 @@ class BasilispNamespaceIndex(Index): shortname = "namespaces" def generate( # pylint: disable=too-many-locals - self, docnames: Optional[Iterable[str]] = None + self, docnames: Iterable[str] | None = None ) -> tuple[list[tuple[str, list[IndexEntry]]], bool]: content: dict[str, list[IndexEntry]] = defaultdict(list) @@ -548,10 +548,10 @@ def resolve_xref( # pylint: disable=too-many-arguments target: str, node: pending_xref, contnode: Element, - ) -> Optional[Element]: + ) -> Element | None: nsname = node.get("lpy:namespace") - maybe_obj: Union[FormEntry, NamespaceEntry, VarEntry, None] + maybe_obj: FormEntry | NamespaceEntry | VarEntry | None reftype = node.get("reftype") if reftype == "ns": maybe_obj = self.namespaces.get(target) diff --git a/src/basilisp/importer.py b/src/basilisp/importer.py index e9df605f..5484e0a7 100644 --- a/src/basilisp/importer.py +++ b/src/basilisp/importer.py @@ -9,7 +9,7 @@ from functools import lru_cache from importlib.abc import MetaPathFinder, SourceLoader from importlib.machinery import ModuleSpec -from typing import Any, Optional, cast +from typing import Any, cast from typing_extensions import TypedDict @@ -144,9 +144,9 @@ def __init__(self): def find_spec( self, fullname: str, - path: Optional[Sequence[str]], - target: Optional[types.ModuleType] = None, - ) -> Optional[ModuleSpec]: + path: Sequence[str] | None, + target: types.ModuleType | None = None, + ) -> ModuleSpec | None: """Find the ModuleSpec for the specified Basilisp module. Returns None if the module is not a Basilisp module to allow import processing to continue. @@ -234,7 +234,7 @@ def get_filename(self, fullname: str) -> str: assert spec is not None, "spec must be defined here" return spec.loader_state["filename"] - def get_code(self, fullname: str) -> Optional[types.CodeType]: + def get_code(self, fullname: str) -> types.CodeType | None: """Return code to load a Basilisp module. This function is part of the ABC for `importlib.abc.ExecutionLoader` which is diff --git a/src/basilisp/lang/atom.py b/src/basilisp/lang/atom.py index dbf85306..8b07eca1 100644 --- a/src/basilisp/lang/atom.py +++ b/src/basilisp/lang/atom.py @@ -1,7 +1,8 @@ import threading -from typing import Callable, Generic, Optional, TypeVar +from collections.abc import Callable +from typing import Concatenate, Generic, TypeVar -from typing_extensions import Concatenate, ParamSpec +from typing_extensions import ParamSpec from basilisp.lang import map as lmap from basilisp.lang.interfaces import IPersistentMap, RefValidator @@ -17,10 +18,10 @@ class Atom(RefBase[T], Generic[T]): def __init__( self, state: T, - meta: Optional[IPersistentMap] = None, - validator: Optional[RefValidator] = None, + meta: IPersistentMap | None = None, + validator: RefValidator | None = None, ) -> None: - self._meta: Optional[IPersistentMap] = meta + self._meta: IPersistentMap | None = meta self._state = state self._lock = threading.RLock() self._watches = lmap.EMPTY diff --git a/src/basilisp/lang/compiler/__init__.py b/src/basilisp/lang/compiler/__init__.py index 1ca6615a..f64368b5 100644 --- a/src/basilisp/lang/compiler/__init__.py +++ b/src/basilisp/lang/compiler/__init__.py @@ -3,9 +3,9 @@ import os import types from ast import unparse -from collections.abc import Iterable +from collections.abc import Callable, Iterable from pathlib import Path -from typing import Any, Callable, Optional +from typing import Any from basilisp.lang import list as llist from basilisp.lang import map as lmap @@ -60,7 +60,7 @@ def to_py_str(t: ast.AST) -> str: class CompilerContext: __slots__ = ("_filename", "_actx", "_gctx", "_optimizer") - def __init__(self, filename: str, opts: Optional[CompilerOpts] = None): + def __init__(self, filename: str, opts: CompilerOpts | None = None): self._filename = filename self._actx = AnalyzerContext(filename=filename, opts=opts) self._gctx = GeneratorContext(filename=filename, opts=opts) @@ -84,15 +84,15 @@ def py_ast_optimizer(self) -> PythonASTOptimizer: def compiler_opts( # pylint: disable=too-many-arguments - generate_auto_inlines: Optional[bool] = None, - inline_functions: Optional[bool] = None, - warn_on_arity_mismatch: Optional[bool] = None, - warn_on_shadowed_name: Optional[bool] = None, - warn_on_shadowed_var: Optional[bool] = None, - warn_on_unused_names: Optional[bool] = None, - warn_on_non_dynamic_set: Optional[bool] = None, - use_var_indirection: Optional[bool] = None, - warn_on_var_indirection: Optional[bool] = None, + generate_auto_inlines: bool | None = None, + inline_functions: bool | None = None, + warn_on_arity_mismatch: bool | None = None, + warn_on_shadowed_name: bool | None = None, + warn_on_shadowed_var: bool | None = None, + warn_on_unused_names: bool | None = None, + warn_on_non_dynamic_set: bool | None = None, + use_var_indirection: bool | None = None, + warn_on_var_indirection: bool | None = None, ) -> CompilerOpts: """Return a map of compiler options with defaults applied.""" return lmap.map( @@ -148,7 +148,7 @@ def compile_and_exec_form( ctx: CompilerContext, ns: runtime.Namespace, wrapped_fn_name: str = _DEFAULT_FN, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> Any: """Compile and execute the given form. This function will be most useful for the REPL and testing purposes. Returns the result of the executed expression. @@ -204,7 +204,7 @@ def _incremental_compile_module( py_ast: GeneratedPyAST, module: BasilispModule, source_filename: str, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> None: """Incrementally compile a stream of AST nodes in module mod. @@ -232,7 +232,7 @@ def _bootstrap_module( gctx: GeneratorContext, optimizer: PythonASTOptimizer, module: BasilispModule, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> None: """Bootstrap a new module with imports and other boilerplate.""" _incremental_compile_module( @@ -249,7 +249,7 @@ def compile_module( forms: Iterable[ReaderForm], ctx: CompilerContext, module: BasilispModule, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> None: """Compile an entire Basilisp module into Python bytecode which can be executed as a Python module. @@ -298,7 +298,7 @@ def load( path: str, ctx: CompilerContext, ns: runtime.Namespace, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> Any: """Call :lpy:fn:`basilisp.core/load` with the given ``path``, returning the result.""" @@ -311,7 +311,7 @@ def load_file( path: Path, ctx: CompilerContext, ns: runtime.Namespace, - collect_bytecode: Optional[BytecodeCollector] = None, + collect_bytecode: BytecodeCollector | None = None, ) -> Any: """Call :lpy:fn:`basilisp.core/load-file` with the given ``path``, returning the result.""" diff --git a/src/basilisp/lang/compiler/analyzer.py b/src/basilisp/lang/compiler/analyzer.py index a73af115..7e8efb9b 100644 --- a/src/basilisp/lang/compiler/analyzer.py +++ b/src/basilisp/lang/compiler/analyzer.py @@ -11,6 +11,7 @@ import uuid from collections import defaultdict from collections.abc import ( + Callable, Collection, Iterable, Iterator, @@ -23,10 +24,9 @@ from fractions import Fraction from functools import partial, wraps from re import Pattern -from typing import Any, Callable, Optional, TypeVar, Union, cast +from typing import Any, Literal, Optional, TypeVar, Union, cast import attr -from typing_extensions import Literal from basilisp.lang import keyword as kw from basilisp.lang import list as llist @@ -233,7 +233,7 @@ def new_symbol( self._table[s] = SymbolTableEntry(binding, warn_if_unused=warn_if_unused) return self - def find_symbol(self, s: sym.Symbol) -> Optional[SymbolTableEntry]: + def find_symbol(self, s: sym.Symbol) -> SymbolTableEntry | None: if s in self._table: return self._table[s] if self._parent is None: @@ -345,8 +345,8 @@ class AnalyzerContext: def __init__( self, - filename: Optional[str] = None, - opts: Optional[CompilerOpts] = None, + filename: str | None = None, + opts: CompilerOpts | None = None, should_macroexpand: bool = True, allow_unresolved_symbols: bool = False, ) -> None: @@ -441,7 +441,7 @@ def should_macroexpand(self) -> bool: return self._should_macroexpand @property - def func_ctx(self) -> Optional[FunctionContext]: + def func_ctx(self) -> FunctionContext | None: """Return the current function or method context of the current node, if one. Return None otherwise. @@ -479,7 +479,7 @@ def new_func_ctx( self._func_ctx.pop() @property - def recur_point(self) -> Optional[RecurPoint]: + def recur_point(self) -> RecurPoint | None: """Return the current recur point which applies to the current node, if there is one.""" try: @@ -509,7 +509,7 @@ def put_new_symbol( # pylint: disable=too-many-arguments warn_on_shadowed_name: bool = True, warn_on_shadowed_var: bool = True, warn_if_unused: bool = True, - symbol_table: Optional[SymbolTable] = None, + symbol_table: SymbolTable | None = None, ): """Add a new symbol to the symbol table. @@ -624,7 +624,7 @@ def syntax_position(self) -> NodeSyntacticPosition: parent node.""" return self._syntax_pos[-1] - def get_node_env(self, pos: Optional[NodeSyntacticPosition] = None) -> NodeEnv: + def get_node_env(self, pos: NodeSyntacticPosition | None = None) -> NodeEnv: """Return the current Node environment. If a syntax position is given, it will be included in the environment. @@ -636,8 +636,8 @@ def get_node_env(self, pos: Optional[NodeSyntacticPosition] = None) -> NodeEnv: def AnalyzerException( self, msg: str, - form: Union[LispForm, None, ISeq] = None, - lisp_ast: Optional[Node] = None, + form: LispForm | None | ISeq = None, + lisp_ast: Node | None = None, ) -> CompilerException: """Return a CompilerException annotated with the current filename and :analyzer compiler phase set. The remaining keyword arguments are passed @@ -664,7 +664,7 @@ def _bool_meta_getter(meta_kw: kw.Keyword, default: bool = False) -> BoolMetaGet """Return a function which checks an object with metadata for a boolean value by meta_kw.""" - def has_meta_prop(o: Union[IMeta, Var]) -> bool: + def has_meta_prop(o: IMeta | Var) -> bool: return bool( Maybe(o.meta).map(lambda m: m.val_at(meta_kw, None)).or_else_get(default) ) @@ -676,7 +676,7 @@ def _meta_getter(meta_kw: kw.Keyword) -> MetaGetter: """Return a function which checks an object with metadata for a value by meta_kw.""" - def get_meta_prop(o: Union[IMeta, Var]) -> Any: + def get_meta_prop(o: IMeta | Var) -> Any: return Maybe(o.meta).map(lambda m: m.val_at(meta_kw, None)).value return get_meta_prop @@ -703,7 +703,7 @@ def get_meta_prop(o: Union[IMeta, Var]) -> Any: LispAnalyzer = Callable[[T_form, AnalyzerContext], T_node] -def _loc(form: T_form) -> Optional[tuple[int, int, int, int]]: +def _loc(form: T_form) -> tuple[int, int, int, int] | None: """Fetch the location of the form in the original filename from the input form, if it has metadata.""" # Technically, IMeta is sufficient for fetching `form.meta` but the @@ -740,7 +740,7 @@ def _analyze_form(form: T_form, ctx: AnalyzerContext) -> T_node: return _analyze_form -def _clean_meta(meta: Optional[lmap.PersistentMap]) -> Optional[lmap.PersistentMap]: +def _clean_meta(meta: lmap.PersistentMap | None) -> lmap.PersistentMap | None: """Remove reader metadata from the form's meta map.""" if meta is None: return None @@ -755,7 +755,7 @@ def _clean_meta(meta: Optional[lmap.PersistentMap]) -> Optional[lmap.PersistentM def _body_ast( - form: Union[llist.PersistentList, ISeq], ctx: AnalyzerContext + form: llist.PersistentList | ISeq, ctx: AnalyzerContext ) -> tuple[Iterable[Node], Node]: """Analyze the form and produce a body of statement nodes and a single return expression node. @@ -845,7 +845,7 @@ def _call_args_ast( return args, kwargs -def _tag_ast(form: Optional[LispForm], ctx: AnalyzerContext) -> Optional[Node]: +def _tag_ast(form: LispForm | None, ctx: AnalyzerContext) -> Node | None: if form is None: return None return _analyze_form(form, ctx) @@ -893,7 +893,7 @@ def with_meta(form: T_form, ctx: AnalyzerContext) -> T_node: @functools.singledispatch -def _analyze_form(form: Union[ReaderForm, ISeq], ctx: AnalyzerContext): +def _analyze_form(form: ReaderForm | ISeq, ctx: AnalyzerContext): raise ctx.AnalyzerException(f"Unexpected form type {type(form)}", form=form) # type: ignore[arg-type] @@ -929,7 +929,7 @@ def _await_ast(form: ISeq, ctx: AnalyzerContext) -> Await: def __should_warn_on_redef( current_ns: runtime.Namespace, defsym: sym.Symbol, - def_meta: Optional[lmap.PersistentMap], + def_meta: lmap.PersistentMap | None, ) -> bool: """Return True if the compiler should emit a warning about this name being redefined.""" if def_meta is not None and def_meta.val_at(SYM_NO_WARN_ON_REDEF_META_KEY, False): @@ -967,7 +967,7 @@ def _def_ast( # pylint: disable=too-many-locals,too-many-statements tag_ast = _tag_ast(_tag_meta(name), ctx) - init_idx: Optional[int] + init_idx: int | None children: vec.PersistentVector[kw.Keyword] if nelems == 2: init_idx = None @@ -1205,11 +1205,11 @@ def __deftype_method_param_bindings( def __deftype_classmethod( # pylint: disable=too-many-locals - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, method_name: str, args: vec.PersistentVector, - kwarg_support: Optional[KeywordArgSupport] = None, + kwarg_support: KeywordArgSupport | None = None, ) -> DefTypeClassMethod: """Emit a node for a :classmethod member of a `deftype*` form.""" with ( @@ -1265,12 +1265,12 @@ def __deftype_classmethod( # pylint: disable=too-many-locals def __deftype_or_reify_method( # pylint: disable=too-many-arguments,too-many-locals - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, method_name: str, args: vec.PersistentVector, special_form: sym.Symbol, - kwarg_support: Optional[KeywordArgSupport] = None, + kwarg_support: KeywordArgSupport | None = None, ) -> DefTypeMethodArity: """Emit a node for a method member of a `deftype*` or `reify*` form.""" assert special_form in {SpecialForm.DEFTYPE, SpecialForm.REIFY} @@ -1329,7 +1329,7 @@ def __deftype_or_reify_method( # pylint: disable=too-many-arguments,too-many-lo def __deftype_or_reify_property( - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, method_name: str, args: vec.PersistentVector, @@ -1394,11 +1394,11 @@ def __deftype_or_reify_property( def __deftype_staticmethod( - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, method_name: str, args: vec.PersistentVector, - kwarg_support: Optional[KeywordArgSupport] = None, + kwarg_support: KeywordArgSupport | None = None, ) -> DefTypeStaticMethod: """Emit a node for a :staticmethod member of a `deftype*` form.""" with ( @@ -1432,10 +1432,10 @@ def __deftype_staticmethod( def __deftype_or_reify_prop_or_method_arity( - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, special_form: sym.Symbol, -) -> Union[DefTypeMethodArity, DefTypePythonMember]: +) -> DefTypeMethodArity | DefTypePythonMember: """Emit either a `deftype*` or `reify*` property node or an arity of a `deftype*` or `reify*` method. @@ -1514,7 +1514,7 @@ def __deftype_or_reify_prop_or_method_arity( def __deftype_or_reify_method_node_from_arities( - form: Union[llist.PersistentList, ISeq], + form: llist.PersistentList | ISeq, ctx: AnalyzerContext, arities: list[DefTypeMethodArity], special_form: sym.Symbol, @@ -1524,7 +1524,7 @@ def __deftype_or_reify_method_node_from_arities( assert special_form in {SpecialForm.DEFTYPE, SpecialForm.REIFY} fixed_arities: MutableSet[int] = set() - fixed_arity_for_variadic: Optional[int] = None + fixed_arity_for_variadic: int | None = None num_variadic = 0 for arity in arities: if arity.is_variadic: @@ -2043,7 +2043,7 @@ def _do_ast(form: ISeq, ctx: AnalyzerContext) -> Do: def __fn_method_ast( # pylint: disable=too-many-locals form: ISeq, ctx: AnalyzerContext, - fnname: Optional[sym.Symbol] = None, + fnname: sym.Symbol | None = None, is_async: bool = False, ) -> FnArity: with ctx.new_symbol_table("fn-method", is_context_boundary=True): @@ -2135,7 +2135,7 @@ def __fn_method_ast( # pylint: disable=too-many-locals return method -def __fn_kwargs_support(ctx: AnalyzerContext, o: IMeta) -> Optional[KeywordArgSupport]: +def __fn_kwargs_support(ctx: AnalyzerContext, o: IMeta) -> KeywordArgSupport | None: if o.meta is None: return None @@ -2169,11 +2169,11 @@ def __unquote_args_sym(f: sym.Symbol, args: frozenset[sym.Symbol]): def _inline_fn_ast( ctx: AnalyzerContext, - form: Union[llist.PersistentList, ISeq], - name: Optional[Binding], + form: llist.PersistentList | ISeq, + name: Binding | None, arities: vec.PersistentVector[FnArity], num_variadic: int, -) -> Optional[Fn]: +) -> Fn | None: if not ctx.should_generate_auto_inlines: return None @@ -2221,7 +2221,7 @@ def _inline_fn_ast( @_with_meta def _fn_ast( # pylint: disable=too-many-locals,too-many-statements - form: Union[llist.PersistentList, ISeq], ctx: AnalyzerContext + form: llist.PersistentList | ISeq, ctx: AnalyzerContext ) -> Fn: assert form.first == SpecialForm.FN @@ -2236,7 +2236,7 @@ def _fn_ast( # pylint: disable=too-many-locals,too-many-statements form=form, ) from e - name_node: Optional[Binding] + name_node: Binding | None inline: InlineMeta if isinstance(name, sym.Symbol): name_node = Binding( @@ -2304,7 +2304,7 @@ def _fn_ast( # pylint: disable=too-many-locals,too-many-statements ) fixed_arities: MutableSet[int] = set() - fixed_arity_for_variadic: Optional[int] = None + fixed_arity_for_variadic: int | None = None num_variadic = 0 for arity in arities: if arity.is_variadic: @@ -2431,7 +2431,7 @@ def _host_prop_ast(form: ISeq, ctx: AnalyzerContext) -> HostField: ) -def _host_interop_ast(form: ISeq, ctx: AnalyzerContext) -> Union[HostCall, HostField]: +def _host_interop_ast(form: ISeq, ctx: AnalyzerContext) -> HostCall | HostField: assert form.first == SpecialForm.INTEROP_CALL nelems = count(form) assert nelems >= 3 @@ -2699,8 +2699,8 @@ def _import_ast(form: ISeq, ctx: AnalyzerContext) -> Import: def __handle_macroexpanded_ast( - original: Union[llist.PersistentList, ISeq], - expanded: Union[ReaderForm, ISeq], + original: llist.PersistentList | ISeq, + expanded: ReaderForm | ISeq, ctx: AnalyzerContext, ) -> Node: """Prepare the Lisp AST from macroexpanded and inlined code.""" @@ -2723,12 +2723,10 @@ def __handle_macroexpanded_ast( def _do_warn_on_arity_mismatch( - fn: VarRef, form: Union[llist.PersistentList, ISeq], ctx: AnalyzerContext + fn: VarRef, form: llist.PersistentList | ISeq, ctx: AnalyzerContext ) -> None: if ctx.warn_on_arity_mismatch and getattr(fn.var.value, "_basilisp_fn", False): - arities: Optional[tuple[Union[int, kw.Keyword]]] = getattr( - fn.var.value, "arities", None - ) + arities: tuple[int | kw.Keyword] | None = getattr(fn.var.value, "arities", None) if arities is not None: has_variadic = REST_KW in arities fixed_arities = set(filter(lambda v: v != REST_KW, arities)) @@ -2756,7 +2754,7 @@ def _do_warn_on_arity_mismatch( ) -def _invoke_ast(form: Union[llist.PersistentList, ISeq], ctx: AnalyzerContext) -> Node: +def _invoke_ast(form: llist.PersistentList | ISeq, ctx: AnalyzerContext) -> Node: with ctx.expr_pos(): fn = _analyze_form(form.first, ctx) @@ -3368,7 +3366,7 @@ def _try_ast(form: ISeq, ctx: AnalyzerContext) -> Try: try_exprs = [] catches = [] - finally_: Optional[Do] = None + finally_: Do | None = None for expr in form.rest: if isinstance(expr, (llist.PersistentList, ISeq)): if expr.first == SpecialForm.CATCH: @@ -3575,7 +3573,7 @@ def __resolve_namespaced_symbol_in_ns( ctx: AnalyzerContext, which_ns: runtime.Namespace, form: sym.Symbol, -) -> Optional[Union[MaybeHostForm, VarRef]]: +) -> MaybeHostForm | VarRef | None: """Resolve the symbol `form` in the context of the Namespace `which_ns`. If `allow_fuzzy_macroexpansion_matching` is True and no match is made on existing imports, import aliases, or namespace aliases, then attempt to match the @@ -3656,7 +3654,7 @@ def __resolve_namespaced_symbol_in_ns( def __resolve_namespaced_symbol( # pylint: disable=too-many-branches ctx: AnalyzerContext, form: sym.Symbol -) -> Union[Const, HostField, MaybeClass, MaybeHostForm, VarRef]: +) -> Const | HostField | MaybeClass | MaybeHostForm | VarRef: """Resolve a namespaced symbol into a Python name or Basilisp Var.""" # Support Clojure 1.12 qualified method names # @@ -3789,7 +3787,7 @@ def __resolve_namespaced_symbol( # pylint: disable=too-many-branches def __resolve_bare_symbol( ctx: AnalyzerContext, form: sym.Symbol -) -> Union[Const, HostField, MaybeClass, VarRef]: +) -> Const | HostField | MaybeClass | VarRef: """Resolve a non-namespaced symbol into a Python name or a local Basilisp Var.""" assert form.ns is None @@ -3858,7 +3856,7 @@ def __resolve_bare_symbol( def _resolve_sym( ctx: AnalyzerContext, form: sym.Symbol -) -> Union[Const, HostField, MaybeClass, MaybeHostForm, VarRef]: +) -> Const | HostField | MaybeClass | MaybeHostForm | VarRef: """Resolve a Basilisp symbol as a Var or Python name.""" # Support special class-name syntax to instantiate new classes # (Classname. *args) @@ -3885,7 +3883,7 @@ def _resolve_sym( @_with_loc def _symbol_node( form: sym.Symbol, ctx: AnalyzerContext -) -> Union[Const, HostField, Local, MaybeClass, MaybeHostForm, VarRef]: +) -> Const | HostField | Local | MaybeClass | MaybeHostForm | VarRef: if ctx.is_quoted: return _const_node(form, ctx) @@ -3905,7 +3903,7 @@ def _symbol_node( @_analyze_form.register(dict) @_with_loc -def _py_dict_node(form: dict, ctx: AnalyzerContext) -> Union[Const, PyDict]: +def _py_dict_node(form: dict, ctx: AnalyzerContext) -> Const | PyDict: if ctx.is_quoted: return _const_node(form, ctx) @@ -3924,7 +3922,7 @@ def _py_dict_node(form: dict, ctx: AnalyzerContext) -> Union[Const, PyDict]: @_analyze_form.register(list) @_with_loc -def _py_list_node(form: list, ctx: AnalyzerContext) -> Union[Const, PyList]: +def _py_list_node(form: list, ctx: AnalyzerContext) -> Const | PyList: if ctx.is_quoted: return _const_node(form, ctx) return PyList( @@ -3936,7 +3934,7 @@ def _py_list_node(form: list, ctx: AnalyzerContext) -> Union[Const, PyList]: @_analyze_form.register(set) @_with_loc -def _py_set_node(form: set, ctx: AnalyzerContext) -> Union[Const, PySet]: +def _py_set_node(form: set, ctx: AnalyzerContext) -> Const | PySet: if ctx.is_quoted: return _const_node(form, ctx) return PySet( @@ -3948,7 +3946,7 @@ def _py_set_node(form: set, ctx: AnalyzerContext) -> Union[Const, PySet]: @_analyze_form.register(tuple) @_with_loc -def _py_tuple_node(form: tuple, ctx: AnalyzerContext) -> Union[Const, PyTuple]: +def _py_tuple_node(form: tuple, ctx: AnalyzerContext) -> Const | PyTuple: if ctx.is_quoted: return _const_node(form, ctx) return PyTuple( @@ -3977,7 +3975,7 @@ def _map_node(form: lmap.PersistentMap, ctx: AnalyzerContext) -> MapNode: @_with_loc def _map_node_or_quoted( form: lmap.PersistentMap, ctx: AnalyzerContext -) -> Union[Const, MapNode]: +) -> Const | MapNode: if ctx.is_quoted: return _const_node(form, ctx) return _map_node(form, ctx) @@ -3996,7 +3994,7 @@ def _queue_node(form: lqueue.PersistentQueue, ctx: AnalyzerContext) -> QueueNode @_with_loc def _queue_node_or_quoted( form: lqueue.PersistentQueue, ctx: AnalyzerContext -) -> Union[Const, QueueNode]: +) -> Const | QueueNode: if ctx.is_quoted: return _const_node(form, ctx) return _queue_node(form, ctx) @@ -4015,7 +4013,7 @@ def _set_node(form: lset.PersistentSet, ctx: AnalyzerContext) -> SetNode: @_with_loc def _set_node_or_quoted( form: lset.PersistentSet, ctx: AnalyzerContext -) -> Union[Const, SetNode]: +) -> Const | SetNode: if ctx.is_quoted: return _const_node(form, ctx) return _set_node(form, ctx) @@ -4034,7 +4032,7 @@ def _vector_node(form: vec.PersistentVector, ctx: AnalyzerContext) -> VectorNode @_with_loc def _vector_node_or_quoted( form: vec.PersistentVector, ctx: AnalyzerContext -) -> Union[Const, VectorNode]: +) -> Const | VectorNode: if ctx.is_quoted: return _const_node(form, ctx) return _vector_node(form, ctx) diff --git a/src/basilisp/lang/compiler/exception.py b/src/basilisp/lang/compiler/exception.py index ea0642ef..3115dc3e 100644 --- a/src/basilisp/lang/compiler/exception.py +++ b/src/basilisp/lang/compiler/exception.py @@ -2,7 +2,7 @@ import os from enum import Enum from types import TracebackType -from typing import Any, Optional, Union +from typing import Any import attr @@ -42,10 +42,10 @@ class CompilerPhase(Enum): @attr.frozen class _loc: - line: Optional[int] = None - col: Optional[int] = None - end_line: Optional[int] = None - end_col: Optional[int] = None + line: int | None = None + col: int | None = None + end_line: int | None = None + end_col: int | None = None def __bool__(self): return ( @@ -61,9 +61,9 @@ class CompilerException(IExceptionInfo): msg: str phase: CompilerPhase filename: str - form: Union[LispForm, None, ISeq] = None - lisp_ast: Optional[Node] = None - py_ast: Optional[Union[ast.expr, ast.stmt]] = None + form: LispForm | None | ISeq = None + lisp_ast: Node | None = None + py_ast: ast.expr | ast.stmt | None = None @property def data(self) -> IPersistentMap: @@ -112,15 +112,15 @@ def __str__(self): @format_exception.register(CompilerException) def format_compiler_exception( # pylint: disable=too-many-branches,unused-argument e: CompilerException, - tp: Optional[type[Exception]] = None, - tb: Optional[TracebackType] = None, - disable_color: Optional[bool] = None, + tp: type[Exception] | None = None, + tb: TracebackType | None = None, + disable_color: bool | None = None, ) -> list[str]: """Format a compiler exception as a list of newline-terminated strings. If `disable_color` is True, no color formatting will be applied to the source code.""" - context_exc: Optional[BaseException] = e.__cause__ + context_exc: BaseException | None = e.__cause__ lines: list[str] = [os.linesep] if context_exc is not None: diff --git a/src/basilisp/lang/compiler/generator.py b/src/basilisp/lang/compiler/generator.py index 431803dc..56a85ac9 100644 --- a/src/basilisp/lang/compiler/generator.py +++ b/src/basilisp/lang/compiler/generator.py @@ -10,7 +10,7 @@ import pickle # nosec B403 import re import uuid -from collections.abc import Collection, Iterable, Mapping, MutableMapping +from collections.abc import Callable, Collection, Iterable, Mapping, MutableMapping from datetime import datetime from decimal import Decimal from enum import Enum @@ -18,10 +18,10 @@ from functools import partial, wraps from itertools import chain from re import Pattern -from typing import TYPE_CHECKING, Callable, Generic, Optional, TypeVar, Union, cast +from typing import TYPE_CHECKING, Concatenate, Generic, Optional, TypeVar, Union, cast import attr -from typing_extensions import Concatenate, ParamSpec +from typing_extensions import ParamSpec from basilisp.lang import keyword as kw from basilisp.lang import list as llist @@ -168,7 +168,7 @@ def new_symbol(self, s: sym.Symbol, munged: str, ctx: LocalType) -> "SymbolTable self._table[s] = SymbolTableEntry(ctx, munged, s) return self - def find_symbol(self, s: sym.Symbol) -> Optional[SymbolTableEntry]: + def find_symbol(self, s: sym.Symbol) -> SymbolTableEntry | None: if s in self._table: return self._table[s] if self._parent is None: @@ -217,8 +217,8 @@ class RecurType(Enum): class RecurPoint: loop_id: str type: RecurType - binding_names: Optional[Iterable[str]] = None - is_variadic: Optional[bool] = None + binding_names: Iterable[str] | None = None + is_variadic: bool | None = None has_recur: bool = False @@ -233,7 +233,7 @@ class GeneratorContext: ) def __init__( - self, filename: Optional[str] = None, opts: Optional[CompilerOpts] = None + self, filename: str | None = None, opts: CompilerOpts | None = None ) -> None: self._filename = Maybe(filename).or_else_get(DEFAULT_COMPILER_FILE_PATH) self._opts = Maybe(opts).map(lmap.map).or_else_get(lmap.m()) # type: ignore @@ -289,8 +289,8 @@ def new_recur_point( self, loop_id: str, type_: RecurType, - binding_names: Optional[Iterable[str]] = None, - is_variadic: Optional[bool] = None, + binding_names: Iterable[str] | None = None, + is_variadic: bool | None = None, ): self._recur_points.append( RecurPoint( @@ -325,9 +325,9 @@ def new_this(self, this: sym.Symbol): def GeneratorException( self, msg: str, - form: Union[LispForm, None, ISeq] = None, - lisp_ast: Optional[Node] = None, - py_ast: Optional[Union[ast.expr, ast.stmt]] = None, + form: LispForm | None | ISeq = None, + lisp_ast: Node | None = None, + py_ast: ast.expr | ast.stmt | None = None, ) -> CompilerException: """Return a CompilerException annotated with the current filename and :code-generation compiler phase set. The remaining keyword arguments are @@ -536,9 +536,9 @@ def _fn_node( # pylint: disable=too-many-arguments args: ast.arguments, body: list[ast.stmt], decorator_list: list[ast.expr], - returns: Optional[ast.expr], + returns: ast.expr | None, is_async: bool, -) -> Union[ast.AsyncFunctionDef, ast.FunctionDef]: +) -> ast.AsyncFunctionDef | ast.FunctionDef: if is_async: return ast_AsyncFunctionDef( name=name, @@ -558,8 +558,8 @@ def _fn_node( # pylint: disable=too-many-arguments def _tagged_assign( - target: ast.Name, value: ast.expr, annotation: Optional[ast.expr] = None -) -> Union[ast.Assign, ast.AnnAssign]: + target: ast.Name, value: ast.expr, annotation: ast.expr | None = None +) -> ast.Assign | ast.AnnAssign: """Return a possibly annotated assignment.""" if annotation is not None: return ast.AnnAssign( @@ -654,7 +654,7 @@ def with_lineno_and_col( MetaNode = Union[Const, MapNode] -def _should_gen_safe_python_param_names(fn_meta_node: Optional[MetaNode]) -> bool: +def _should_gen_safe_python_param_names(fn_meta_node: MetaNode | None) -> bool: """Return True if the `fn_meta_node` has the meta key set to generate globally unique function parameter names.""" return ( @@ -831,8 +831,8 @@ def statementize(e: PyASTNode) -> ast.stmt: def expressionize( body: GeneratedPyAST, fn_name: str, - args: Optional[Iterable[ast.arg]] = None, - vargs: Optional[ast.arg] = None, + args: Iterable[ast.arg] | None = None, + vargs: ast.arg | None = None, ) -> ast.FunctionDef: """Given a series of expression AST nodes, create a function AST node with the given name that can be called and will return the result of @@ -929,7 +929,7 @@ def _def_to_py_ast( # pylint: disable=too-many-locals def_ast = gen_py_ast(ctx, node.init) is_defn = False - tag: Optional[ast.expr] + tag: ast.expr | None tag_deps: Iterable[PyASTNode] if node.tag is not None and (tag_ast := gen_py_ast(ctx, node.tag)) is not None: tag = tag_ast.node @@ -1095,8 +1095,8 @@ def __deftype_property_to_py_ast( def __multi_arity_deftype_dispatch_method( name: str, arity_map: Mapping[int, str], - default_name: Optional[str] = None, - max_fixed_arity: Optional[int] = None, + default_name: str | None = None, + max_fixed_arity: int | None = None, ) -> GeneratedPyAST[ast.stmt]: """Return the Python AST nodes for an argument-length dispatch method for multi-arity `deftype*` or `reify*` methods. @@ -1135,7 +1135,7 @@ def method(self, *args): """ method_prefix = genname("self") - dispatch_keys: list[Optional[ast.expr]] = [] + dispatch_keys: list[ast.expr | None] = [] dispatch_vals: list[ast.expr] = [] for k, v in arity_map.items(): dispatch_keys.append(ast.Constant(k)) @@ -1266,7 +1266,7 @@ def __multi_arity_deftype_method_to_py_ast( ) arity_to_name = {} - rest_arity_name: Optional[str] = None + rest_arity_name: str | None = None fn_defs = [] for arity in arities: arity_name = arity.python_name @@ -1301,7 +1301,7 @@ def __deftype_method_arity_to_py_ast( ctx: GeneratorContext, node: DefTypeMethod, arity: DefTypeMethodArity, - method_name: Optional[str] = None, + method_name: str | None = None, ) -> GeneratedPyAST[ast.stmt]: assert arity.op == NodeOp.DEFTYPE_METHOD_ARITY assert node.name == arity.name @@ -1417,7 +1417,7 @@ def __deftype_member_to_py_ast( def __deftype_or_reify_bases_to_py_ast( ctx: GeneratorContext, - node: Union[DefType, Reify], + node: DefType | Reify, interfaces: Iterable[DefTypeBase], ) -> list[ast.expr]: """Return a list of AST nodes for the base classes for a `deftype*` or `reify*`.""" @@ -1490,7 +1490,7 @@ def _deftype_to_py_ast( # pylint: disable=too-many-locals else: attr_default_kws = [] - tag: Optional[ast.expr] = None + tag: ast.expr | None = None if ( field.tag is not None and (tag_ast := gen_py_ast(ctx, field.tag)) is not None @@ -1640,7 +1640,7 @@ def _synthetic_do_to_py_ast( ) -def __fn_name(ctx: GeneratorContext, s: Optional[str]) -> str: +def __fn_name(ctx: GeneratorContext, s: str | None) -> str: """Generate a safe Python function name from a function name symbol. If no symbol is provided, generate a name with a default prefix. @@ -1659,7 +1659,7 @@ def __fn_args_to_py_ast( params: Iterable[Binding], body: Do, should_generate_safe_names: bool = False, -) -> tuple[list[ast.arg], Optional[ast.arg], list[ast.stmt], Iterable[PyASTNode]]: +) -> tuple[list[ast.arg], ast.arg | None, list[ast.stmt], Iterable[PyASTNode]]: """Generate a list of Python AST nodes from function method parameters. Parameter names are munged and modified to ensure global @@ -1681,7 +1681,7 @@ def __fn_args_to_py_ast( if should_generate_safe_names or binding.name == "_": arg_name = genname(arg_name) - arg_tag: Optional[ast.expr] + arg_tag: ast.expr | None if ( binding.tag is not None and (arg_tag_ast := gen_py_ast(ctx, binding.tag)) is not None @@ -1771,7 +1771,7 @@ def __fn_decorator( def __fn_meta( - ctx: GeneratorContext, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, meta_node: MetaNode | None = None ) -> tuple[Iterable[PyASTNode], Iterable[ast.expr]]: if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) @@ -1790,7 +1790,7 @@ def __fn_meta( def __kwargs_support_decorator( - node: Union[Fn, DefTypeMethodArity, DefTypeClassMethod, DefTypeStaticMethod], + node: Fn | DefTypeMethodArity | DefTypeClassMethod | DefTypeStaticMethod, ) -> Iterable[ast.expr]: if node.kwarg_support is None: return @@ -1806,8 +1806,8 @@ def __single_arity_fn_to_py_ast( # pylint: disable=too-many-locals ctx: GeneratorContext, node: Fn, method: FnArity, - def_name: Optional[str] = None, - meta_node: Optional[MetaNode] = None, + def_name: str | None = None, + meta_node: MetaNode | None = None, ) -> GeneratedPyAST[ast.expr]: """Return a Python AST node for a function with a single arity.""" assert node.op == NodeOp.FN @@ -1834,7 +1834,7 @@ def __single_arity_fn_to_py_ast( # pylint: disable=too-many-locals ) meta_deps, meta_decorators = __fn_meta(ctx, meta_node) - ret_ann_tag: Optional[ast.expr] + ret_ann_tag: ast.expr | None ret_ann_deps: Iterable[PyASTNode] if ( method.tag is not None @@ -1903,11 +1903,11 @@ def __multi_arity_dispatch_fn( # pylint: disable=too-many-arguments,too-many-lo ctx: GeneratorContext, name: str, arity_map: Mapping[int, str], - return_tags: Iterable[Optional[Node]], - default_name: Optional[str] = None, - rest_arity_fixed_arity: Optional[int] = None, - max_fixed_arity: Optional[int] = None, - meta_node: Optional[MetaNode] = None, + return_tags: Iterable[Node | None], + default_name: str | None = None, + rest_arity_fixed_arity: int | None = None, + max_fixed_arity: int | None = None, + meta_node: MetaNode | None = None, is_async: bool = False, ) -> GeneratedPyAST[ast.expr]: """Return the Python AST nodes for a argument-length dispatch function @@ -1925,7 +1925,7 @@ def fn(*args): """ dispatch_map_name = f"{name}_dispatch_map" - dispatch_keys: list[Optional[ast.expr]] = [] + dispatch_keys: list[ast.expr | None] = [] dispatch_vals: list[ast.expr] = [] for k, v in arity_map.items(): dispatch_keys.append(ast.Constant(k)) @@ -2025,7 +2025,7 @@ def fn(*args): meta_deps, meta_decorators = __fn_meta(ctx, meta_node) - ret_ann_ast: Optional[ast.expr] = None + ret_ann_ast: ast.expr | None = None ret_ann_deps: list[PyASTNode] = [] if all(tag is not None for tag in return_tags): ret_ann_asts: list[ast.expr] = [] @@ -2100,8 +2100,8 @@ def __multi_arity_fn_to_py_ast( # pylint: disable=too-many-locals ctx: GeneratorContext, node: Fn, arities: Collection[FnArity], - def_name: Optional[str] = None, - meta_node: Optional[MetaNode] = None, + def_name: str | None = None, + meta_node: MetaNode | None = None, ) -> GeneratedPyAST[ast.expr]: """Return a Python AST node for a function with multiple arities.""" assert node.op == NodeOp.FN @@ -2112,8 +2112,8 @@ def __multi_arity_fn_to_py_ast( # pylint: disable=too-many-locals py_fn_name = __fn_name(ctx, lisp_fn_name) if def_name is None else munge(def_name) arity_to_name = {} - rest_arity_name: Optional[str] = None - rest_arity_fixed_arity: Optional[int] = None + rest_arity_name: str | None = None + rest_arity_fixed_arity: int | None = None fn_defs = [] all_arity_def_deps: list[PyASTNode] = [] for arity in arities: @@ -2149,7 +2149,7 @@ def __multi_arity_fn_to_py_ast( # pylint: disable=too-many-locals ) all_arity_def_deps.extend(fn_def_deps) - ret_ann_tag: Optional[ast.expr] + ret_ann_tag: ast.expr | None if ( arity.tag is not None and (ret_ann_ast := gen_py_ast(ctx, arity.tag)) is not None @@ -2205,8 +2205,8 @@ def __multi_arity_fn_to_py_ast( # pylint: disable=too-many-locals def _fn_to_py_ast( ctx: GeneratorContext, node: Fn, - def_name: Optional[str] = None, - meta_node: Optional[MetaNode] = None, + def_name: str | None = None, + meta_node: MetaNode | None = None, ) -> GeneratedPyAST[ast.expr]: """Return a Python AST Node for a `fn` expression.""" assert node.op == NodeOp.FN @@ -2222,7 +2222,7 @@ def _fn_to_py_ast( @_with_ast_loc_deps def __if_body_to_py_ast( - ctx: GeneratorContext, node: Node, result_name: Optional[str] + ctx: GeneratorContext, node: Node, result_name: str | None ) -> GeneratedPyAST: """Generate custom `if` nodes to handle `recur` bodies. @@ -2410,7 +2410,7 @@ def _import_to_py_ast(ctx: GeneratorContext, node: Import) -> GeneratedPyAST[ast ) ) - refers: Optional[ast.expr] = None + refers: ast.expr | None = None if alias.refer_all: key, val = genname("k"), genname("v") refers = ast.DictComp( @@ -2448,7 +2448,7 @@ def _import_to_py_ast(ctx: GeneratorContext, node: Import) -> GeneratedPyAST[ast ], ) elif alias.refers: - refer_keys: list[Optional[ast.expr]] = [] + refer_keys: list[ast.expr | None] = [] refer_vals: list[ast.expr] = [] for refer in alias.refers: refer_keys.append( @@ -2536,7 +2536,7 @@ def _let_to_py_ast(ctx: GeneratorContext, node: Let) -> GeneratedPyAST[ast.expr] assert init_node is not None init_ast = gen_py_ast(ctx, init_node) - tag: Optional[ast.expr] + tag: ast.expr | None if ( binding.tag is not None and (tag_ast := gen_py_ast(ctx, binding.tag)) is not None @@ -2797,12 +2797,12 @@ def _recur_to_py_ast(ctx: GeneratorContext, node: Recur) -> GeneratedPyAST[ast.e @_with_ast_loc def _reify_to_py_ast( - ctx: GeneratorContext, node: Reify, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, node: Reify, meta_node: MetaNode | None = None ) -> GeneratedPyAST[ast.expr]: """Return a Python AST Node for a `reify*` expression.""" assert node.op == NodeOp.REIFY - meta_ast: Optional[GeneratedPyAST] + meta_ast: GeneratedPyAST | None if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) else: @@ -3108,7 +3108,7 @@ def _throw_to_py_ast(ctx: GeneratorContext, node: Throw) -> GeneratedPyAST[ast.e exc_ast = gen_py_ast(ctx, node.exception) - cause: Optional[ast.expr] + cause: ast.expr | None cause_deps: Iterable[PyASTNode] if ( node.cause is not None @@ -3250,7 +3250,7 @@ def _local_sym_to_py_ast( ) -def __name_in_module(name: str, module: BasilispModule) -> Optional[str]: +def __name_in_module(name: str, module: BasilispModule) -> str | None: """Resolve the name inside of module. If the munged name can be found inside the module, return the munged name. Return None otherwise.""" safe_name = munge(name) @@ -3264,7 +3264,7 @@ def __var_direct_link_to_py_ast( current_ns: runtime.Namespace, var: runtime.Var, py_var_ctx: PyASTCtx, -) -> Optional[GeneratedPyAST[ast.expr]]: +) -> GeneratedPyAST[ast.expr] | None: """Attempt to directly link a Var reference to a Python variable in the module of the current Namespace. @@ -3473,11 +3473,11 @@ def _maybe_host_form_to_py_ast( @_with_ast_loc def _map_to_py_ast( - ctx: GeneratorContext, node: MapNode, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, node: MapNode, meta_node: MetaNode | None = None ) -> GeneratedPyAST[ast.expr]: assert node.op == NodeOp.MAP - meta_ast: Optional[GeneratedPyAST] + meta_ast: GeneratedPyAST | None if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) else: @@ -3505,11 +3505,11 @@ def _map_to_py_ast( @_with_ast_loc def _queue_to_py_ast( - ctx: GeneratorContext, node: QueueNode, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, node: QueueNode, meta_node: MetaNode | None = None ) -> GeneratedPyAST[ast.expr]: assert node.op == NodeOp.QUEUE - meta_ast: Optional[GeneratedPyAST] + meta_ast: GeneratedPyAST | None if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) else: @@ -3534,11 +3534,11 @@ def _queue_to_py_ast( @_with_ast_loc def _set_to_py_ast( - ctx: GeneratorContext, node: SetNode, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, node: SetNode, meta_node: MetaNode | None = None ) -> GeneratedPyAST[ast.expr]: assert node.op == NodeOp.SET - meta_ast: Optional[GeneratedPyAST] + meta_ast: GeneratedPyAST | None if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) else: @@ -3563,11 +3563,11 @@ def _set_to_py_ast( @_with_ast_loc def _vec_to_py_ast( - ctx: GeneratorContext, node: VectorNode, meta_node: Optional[MetaNode] = None + ctx: GeneratorContext, node: VectorNode, meta_node: MetaNode | None = None ) -> GeneratedPyAST[ast.expr]: assert node.op == NodeOp.VECTOR - meta_ast: Optional[GeneratedPyAST] + meta_ast: GeneratedPyAST | None if meta_node is not None: meta_ast = gen_py_ast(ctx, meta_node) else: @@ -3717,7 +3717,7 @@ def _collection_literal_to_py_ast( def _const_meta_kwargs_ast( ctx: GeneratorContext, form: LispForm -) -> Optional[GeneratedPyAST]: +) -> GeneratedPyAST | None: if isinstance(form, IMeta) and form.meta is not None: genned = _const_val_to_py_ast(_clean_meta(form), ctx) return GeneratedPyAST( @@ -3736,7 +3736,7 @@ def _const_meta_kwargs_ast( @_const_val_to_py_ast.register(int) @_const_val_to_py_ast.register(str) @_simple_ast_generator -def _py_const_to_py_ast(form: Union[bool, None], _: GeneratorContext) -> ast.Constant: +def _py_const_to_py_ast(form: bool | None, _: GeneratorContext) -> ast.Constant: return ast.Constant(form) @@ -3920,7 +3920,7 @@ def _const_set_to_py_ast( @_const_val_to_py_ast.register(llist.PersistentList) @_const_val_to_py_ast.register(ISeq) def _const_seq_to_py_ast( - form: Union[llist.PersistentList, ISeq], ctx: GeneratorContext + form: llist.PersistentList | ISeq, ctx: GeneratorContext ) -> GeneratedPyAST[ast.expr]: elem_deps, elems = _chain_py_ast(*_collection_literal_to_py_ast(ctx, form)) diff --git a/src/basilisp/lang/compiler/nodes.py b/src/basilisp/lang/compiler/nodes.py index ff460554..6062ac85 100644 --- a/src/basilisp/lang/compiler/nodes.py +++ b/src/basilisp/lang/compiler/nodes.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod -from collections.abc import Iterable, MutableMapping, Sequence +from collections.abc import Callable, Iterable, MutableMapping, Sequence from enum import Enum -from typing import Any, Callable, Generic, Optional, TypeVar, Union +from typing import Any, Generic, Optional, TypeVar, Union import attr @@ -186,7 +186,7 @@ def visit(self, f: Callable[..., None], *args, **kwargs): f(child, *args, **kwargs) def fix_missing_locations( - self, form_loc: Optional[tuple[int, int, int, int]] = None + self, form_loc: tuple[int, int, int, int] | None = None ) -> "Node[T]": """Return a transformed copy of this node with location in this node's environment updated to match the `form_loc` if given, or using its @@ -207,7 +207,7 @@ def fix_missing_locations( e is not None for e in loc ), "Must specify location information" - new_attrs: MutableMapping[str, Union[NodeEnv, Node, Iterable[Node]]] = { + new_attrs: MutableMapping[str, NodeEnv | Node | Iterable[Node]] = { "env": attr.evolve( self.env, line=loc[0], col=loc[1], end_line=loc[2], end_col=loc[3] ) @@ -330,12 +330,12 @@ class LocalType(Enum): class NodeEnv: ns: Namespace file: str - line: Optional[int] = None - col: Optional[int] = None - end_line: Optional[int] = None - end_col: Optional[int] = None - pos: Optional[NodeSyntacticPosition] = None - func_ctx: Optional[FunctionContext] = None + line: int | None = None + col: int | None = None + end_line: int | None = None + end_col: int | None = None + pos: NodeSyntacticPosition | None = None + func_ctx: FunctionContext | None = None @attr.frozen @@ -355,11 +355,11 @@ class Binding(Node[sym.Symbol], Assignable): name: str local: LocalType env: NodeEnv = attr.field(hash=False) - tag: Optional[Node] = None - arg_id: Optional[int] = None + tag: Node | None = None + arg_id: int | None = None is_variadic: bool = False is_assignable: bool = False - init: Optional[Node] = None + init: Node | None = None meta: NodeMeta = None children: Sequence[kw.Keyword] = vec.EMPTY op: NodeOp = NodeOp.BINDING @@ -399,10 +399,10 @@ class Def(Node[SpecialForm]): form: SpecialForm name: sym.Symbol var: Var - init: Optional[Node] - doc: Optional[str] + init: Node | None + doc: str | None env: NodeEnv = attr.field(hash=False) - tag: Optional[Node] = None + tag: Node | None = None meta: NodeMeta = None children: Sequence[kw.Keyword] = vec.EMPTY op: NodeOp = NodeOp.DEF @@ -455,7 +455,7 @@ class DefTypeClassMethod(DefTypeMember): fixed_arity: int body: "Do" is_variadic: bool = False - kwarg_support: Optional[KeywordArgSupport] = None + kwarg_support: KeywordArgSupport | None = None children: Sequence[kw.Keyword] = vec.v(CLASS_LOCAL, PARAMS, BODY) op: NodeOp = NodeOp.DEFTYPE_CLASSMETHOD top_level: bool = False @@ -484,7 +484,7 @@ class DefTypeMethodArity(Node[SpecialForm]): loop_id: LoopID env: NodeEnv = attr.field(hash=False) is_variadic: bool = False - kwarg_support: Optional[KeywordArgSupport] = None + kwarg_support: KeywordArgSupport | None = None children: Sequence[kw.Keyword] = vec.v(THIS_LOCAL, PARAMS, BODY) op: NodeOp = NodeOp.DEFTYPE_METHOD_ARITY top_level: bool = False @@ -512,7 +512,7 @@ class DefTypeStaticMethod(DefTypeMember): fixed_arity: int body: "Do" is_variadic: bool = False - kwarg_support: Optional[KeywordArgSupport] = None + kwarg_support: KeywordArgSupport | None = None children: Sequence[kw.Keyword] = vec.v(PARAMS, BODY) op: NodeOp = NodeOp.DEFTYPE_STATICMETHOD top_level: bool = False @@ -542,10 +542,10 @@ class Fn(Node[SpecialForm]): max_fixed_arity: int arities: IPersistentVector["FnArity"] env: NodeEnv = attr.field(hash=False) - local: Optional[Binding] = None + local: Binding | None = None is_variadic: bool = False is_async: bool = False - kwarg_support: Optional[KeywordArgSupport] = None + kwarg_support: KeywordArgSupport | None = None inline_fn: Optional["Fn"] = None children: Sequence[kw.Keyword] = vec.v(ARITIES) op: NodeOp = NodeOp.FN @@ -561,7 +561,7 @@ class FnArity(Node[SpecialForm]): fixed_arity: int body: Do env: NodeEnv = attr.field(hash=False) - tag: Optional[Node] = None + tag: Node | None = None is_variadic: bool = False children: Sequence[kw.Keyword] = vec.v(PARAMS, BODY) op: NodeOp = NodeOp.FN_ARITY @@ -585,7 +585,7 @@ class HostCall(Node[SpecialForm]): @attr.frozen class HostField(Node[Union[SpecialForm, sym.Symbol]], Assignable): - form: Union[SpecialForm, sym.Symbol] + form: SpecialForm | sym.Symbol field: str target: Node env: NodeEnv = attr.field(hash=False) @@ -622,9 +622,9 @@ class Import(Node[SpecialForm]): @attr.frozen class ImportAlias(Node[Union[sym.Symbol, vec.PersistentVector]]): - form: Union[sym.Symbol, vec.PersistentVector] + form: sym.Symbol | vec.PersistentVector name: str - alias: Optional[str] + alias: str | None refers: Iterable[str] refer_all: bool env: NodeEnv = attr.field(hash=False) @@ -678,7 +678,7 @@ class Local(Node[sym.Symbol], Assignable): local: LocalType env: NodeEnv = attr.field(hash=False) is_assignable: bool = False - arg_id: Optional[int] = None + arg_id: int | None = None is_variadic: bool = False children: Sequence[kw.Keyword] = vec.EMPTY op: NodeOp = NodeOp.LOCAL @@ -761,7 +761,7 @@ class PyList(Node[list]): @attr.frozen(eq=True) class PySet(Node[Union[frozenset, set]]): - form: Union[frozenset, set] + form: frozenset | set items: Iterable[Node] env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.v(ITEMS) @@ -839,9 +839,9 @@ def python_member_names(self) -> Iterable[str]: @attr.frozen class RequireAlias(Node[Union[sym.Symbol, vec.PersistentVector]]): - form: Union[sym.Symbol, vec.PersistentVector] + form: sym.Symbol | vec.PersistentVector name: str - alias: Optional[str] + alias: str | None env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.EMPTY op: NodeOp = NodeOp.REQUIRE_ALIAS @@ -874,7 +874,7 @@ class Set(Node[IPersistentSet]): @attr.frozen class SetBang(Node[SpecialForm]): form: SpecialForm - target: Union[Assignable, Node] + target: Assignable | Node val: Node env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.v(TARGET, VAL) @@ -887,7 +887,7 @@ class SetBang(Node[SpecialForm]): class Throw(Node[SpecialForm]): form: SpecialForm exception: Node - cause: Optional[Node] + cause: Node | None env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.v(EXCEPTION) op: NodeOp = NodeOp.THROW @@ -902,7 +902,7 @@ class Try(Node[SpecialForm]): catches: Iterable[Catch] children: Sequence[kw.Keyword] env: NodeEnv = attr.field(hash=False) - finally_: Optional[Do] = None + finally_: Do | None = None op: NodeOp = NodeOp.TRY top_level: bool = False raw_forms: IPersistentVector[LispForm] = vec.EMPTY @@ -910,7 +910,7 @@ class Try(Node[SpecialForm]): @attr.frozen class VarRef(Node[Union[sym.Symbol, ISeq]], Assignable): - form: Union[sym.Symbol, ISeq] + form: sym.Symbol | ISeq var: Var env: NodeEnv = attr.field(hash=False) return_var: bool = False @@ -939,7 +939,7 @@ class Vector(Node[IPersistentVector]): @attr.frozen class WithMeta(Node[LispForm], Generic[T_withmeta]): form: LispForm - meta: Union[Const, Map] + meta: Const | Map expr: T_withmeta env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.v(META, EXPR) @@ -951,7 +951,7 @@ class WithMeta(Node[LispForm], Generic[T_withmeta]): @attr.frozen class Yield(Node[SpecialForm]): form: SpecialForm - expr: Optional[Node] + expr: Node | None env: NodeEnv = attr.field(hash=False) children: Sequence[kw.Keyword] = vec.v(EXPR) op: NodeOp = NodeOp.YIELD diff --git a/src/basilisp/lang/compiler/optimizer.py b/src/basilisp/lang/compiler/optimizer.py index 3e989c50..9252dfb9 100644 --- a/src/basilisp/lang/compiler/optimizer.py +++ b/src/basilisp/lang/compiler/optimizer.py @@ -3,7 +3,7 @@ from collections import deque from collections.abc import Iterable from contextlib import contextmanager -from typing import Deque, Optional +from typing import Deque from basilisp.lang.compiler.constants import OPERATOR_ALIAS from basilisp.lang.compiler.utils import ast_FunctionDef @@ -150,7 +150,7 @@ def visit_Call(self, node: ast.Call) -> ast.AST: ) return new_node - def visit_ExceptHandler(self, node: ast.ExceptHandler) -> Optional[ast.AST]: + def visit_ExceptHandler(self, node: ast.ExceptHandler) -> ast.AST | None: """Eliminate dead code from except handler bodies.""" new_node = self.generic_visit(node) assert isinstance(new_node, ast.ExceptHandler) @@ -163,14 +163,14 @@ def visit_ExceptHandler(self, node: ast.ExceptHandler) -> Optional[ast.AST]: new_node, ) - def visit_Expr(self, node: ast.Expr) -> Optional[ast.Expr]: + def visit_Expr(self, node: ast.Expr) -> ast.Expr | None: """Eliminate no-op constant expressions which are in the tree as standalone statements.""" if isinstance(node.value, (ast.Constant, ast.Name)): return None return node - def visit_FunctionDef(self, node: ast.FunctionDef) -> Optional[ast.AST]: + def visit_FunctionDef(self, node: ast.FunctionDef) -> ast.AST | None: """Eliminate dead code from function bodies.""" with self._new_global_context(): new_node = self.generic_visit(node) @@ -186,7 +186,7 @@ def visit_FunctionDef(self, node: ast.FunctionDef) -> Optional[ast.AST]: new_node, ) - def visit_Global(self, node: ast.Global) -> Optional[ast.Global]: + def visit_Global(self, node: ast.Global) -> ast.Global | None: """Eliminate redundant name declarations inside a Python `global` statement. Python `global` statements may only refer to a name prior to its declaration. @@ -201,7 +201,7 @@ def visit_Global(self, node: ast.Global) -> Optional[ast.Global]: else None ) - def visit_If(self, node: ast.If) -> Optional[ast.AST]: + def visit_If(self, node: ast.If) -> ast.AST | None: """Eliminate dead code from if/elif bodies. If the new `if` statement `body` is empty after eliminating dead code, replace @@ -232,7 +232,7 @@ def visit_If(self, node: ast.If) -> Optional[ast.AST]: return ast.copy_location(ifstmt, new_node) - def visit_While(self, node: ast.While) -> Optional[ast.AST]: + def visit_While(self, node: ast.While) -> ast.AST | None: """Eliminate dead code from while bodies.""" new_node = self.generic_visit(node) assert isinstance(new_node, ast.While) @@ -245,7 +245,7 @@ def visit_While(self, node: ast.While) -> Optional[ast.AST]: new_node, ) - def visit_Try(self, node: ast.Try) -> Optional[ast.AST]: + def visit_Try(self, node: ast.Try) -> ast.AST | None: """Eliminate dead code from except try bodies.""" new_node = self.generic_visit(node) assert isinstance(new_node, ast.Try) diff --git a/src/basilisp/lang/delay.py b/src/basilisp/lang/delay.py index 03270e70..6b56f60d 100644 --- a/src/basilisp/lang/delay.py +++ b/src/basilisp/lang/delay.py @@ -1,4 +1,5 @@ -from typing import Callable, Generic, Optional, TypeVar +from collections.abc import Callable +from typing import Generic, TypeVar import attr @@ -11,7 +12,7 @@ @attr.frozen class _DelayState(Generic[T]): f: Callable[[], T] - value: Optional[T] + value: T | None computed: bool = False @@ -28,7 +29,7 @@ def __deref(state: _DelayState) -> _DelayState: else: return _DelayState(f=state.f, value=state.f(), computed=True) - def deref(self) -> Optional[T]: + def deref(self) -> T | None: return self._state.swap(self.__deref).value @property diff --git a/src/basilisp/lang/exception.py b/src/basilisp/lang/exception.py index 43be9bd0..32f10c7e 100644 --- a/src/basilisp/lang/exception.py +++ b/src/basilisp/lang/exception.py @@ -2,7 +2,6 @@ import sys import traceback from types import TracebackType -from typing import Optional import attr @@ -26,10 +25,10 @@ def __str__(self): @functools.singledispatch def format_exception( # pylint: disable=unused-argument - e: Optional[BaseException], - tp: Optional[type[BaseException]] = None, - tb: Optional[TracebackType] = None, - disable_color: Optional[bool] = None, + e: BaseException | None, + tp: type[BaseException] | None = None, + tb: TracebackType | None = None, + disable_color: bool | None = None, ) -> list[str]: """Format an exception into something readable, returning a list of newline terminated strings. @@ -49,9 +48,9 @@ def format_exception( # pylint: disable=unused-argument def print_exception( - e: Optional[BaseException], - tp: Optional[type[BaseException]] = None, - tb: Optional[TracebackType] = None, + e: BaseException | None, + tp: type[BaseException] | None = None, + tb: TracebackType | None = None, ) -> None: """Print the given exception `e` using Basilisp's own exception formatting. diff --git a/src/basilisp/lang/futures.py b/src/basilisp/lang/futures.py index 9830212b..f69308b4 100644 --- a/src/basilisp/lang/futures.py +++ b/src/basilisp/lang/futures.py @@ -1,8 +1,9 @@ +from collections.abc import Callable from concurrent.futures import Future as _Future # noqa # pylint: disable=unused-import from concurrent.futures import ProcessPoolExecutor as _ProcessPoolExecutor from concurrent.futures import ThreadPoolExecutor as _ThreadPoolExecutor from concurrent.futures import TimeoutError as _TimeoutError -from typing import Callable, Optional, TypeVar +from typing import TypeVar import attr from typing_extensions import ParamSpec @@ -27,8 +28,8 @@ def cancelled(self) -> bool: return self._future.cancelled() def deref( - self, timeout: Optional[float] = None, timeout_val: Optional[T] = None - ) -> Optional[T]: + self, timeout: float | None = None, timeout_val: T | None = None + ) -> T | None: try: return self._future.result(timeout=timeout) except _TimeoutError: @@ -43,7 +44,7 @@ def is_realized(self) -> bool: # Pass `Future.result(timeout=...)` through so `Executor.map(...)` can # still work with this Future wrapper. - def result(self, timeout: Optional[float] = None) -> T: + def result(self, timeout: float | None = None) -> T: return self._future.result(timeout=timeout) @@ -53,7 +54,7 @@ def result(self, timeout: Optional[float] = None) -> T: class ProcessPoolExecutor(_ProcessPoolExecutor): # pragma: no cover - def __init__(self, max_workers: Optional[int] = None): + def __init__(self, max_workers: int | None = None): super().__init__(max_workers=max_workers) # pylint: disable=arguments-differ @@ -66,7 +67,7 @@ def submit( # type: ignore[override] class ThreadPoolExecutor(_ThreadPoolExecutor): def __init__( self, - max_workers: Optional[int] = None, + max_workers: int | None = None, thread_name_prefix: str = "basilisp-futures", ): super().__init__(max_workers=max_workers, thread_name_prefix=thread_name_prefix) diff --git a/src/basilisp/lang/interfaces.py b/src/basilisp/lang/interfaces.py index c29ed9f0..fc16fca3 100644 --- a/src/basilisp/lang/interfaces.py +++ b/src/basilisp/lang/interfaces.py @@ -1,10 +1,17 @@ import itertools from abc import ABC, abstractmethod -from collections.abc import Hashable, Iterable, Iterator, Mapping, Sequence, Sized +from collections.abc import ( + Callable, + Hashable, + Iterable, + Iterator, + Mapping, + Sequence, + Sized, +) from typing import ( AbstractSet, Any, - Callable, Final, Generic, Optional, @@ -33,7 +40,7 @@ class IDeref(Generic[T], ABC): __slots__ = () @abstractmethod - def deref(self) -> Optional[T]: + def deref(self) -> T | None: raise NotImplementedError() @@ -50,8 +57,8 @@ class IBlockingDeref(IDeref[T]): @abstractmethod def deref( - self, timeout: Optional[float] = None, timeout_val: Optional[T] = None - ) -> Optional[T]: + self, timeout: float | None = None, timeout_val: T | None = None + ) -> T | None: raise NotImplementedError() @@ -178,12 +185,12 @@ def name(self) -> str: @property @abstractmethod - def ns(self) -> Optional[str]: + def ns(self) -> str | None: raise NotImplementedError() @classmethod @abstractmethod - def with_name(cls, name: str, ns: Optional[str] = None) -> Self: + def with_name(cls, name: str, ns: str | None = None) -> Self: """Create a new instance of this INamed with `name` and optional `ns`.""" raise NotImplementedError() @@ -239,11 +246,11 @@ def remove_watch(self, k: RefWatchKey) -> "IReference": raise NotImplementedError() @abstractmethod - def get_validator(self) -> Optional[RefValidator[T]]: + def get_validator(self) -> RefValidator[T] | None: raise NotImplementedError() @abstractmethod - def set_validator(self, vf: Optional[RefValidator[T]] = None) -> None: + def set_validator(self, vf: RefValidator[T] | None = None) -> None: raise NotImplementedError() @@ -304,7 +311,7 @@ class ILookup(Generic[K, V], ABC): __slots__ = () @abstractmethod - def val_at(self, k: K, default: Optional[V] = None) -> Optional[V]: + def val_at(self, k: K, default: V | None = None) -> V | None: raise NotImplementedError() @@ -364,7 +371,7 @@ def contains(self, k: K) -> bool: raise NotImplementedError() @abstractmethod - def entry(self, k: K) -> Optional[IMapEntry[K, V]]: + def entry(self, k: K) -> IMapEntry[K, V] | None: raise NotImplementedError() @@ -380,7 +387,7 @@ class IPersistentStack(IPersistentCollection[T]): __slots__ = () @abstractmethod - def peek(self) -> Optional[T]: + def peek(self) -> T | None: raise NotImplementedError() @abstractmethod @@ -605,7 +612,7 @@ def contains_transient(self, k: K) -> bool: raise NotImplementedError() @abstractmethod - def entry_transient(self, k: K) -> Optional[IMapEntry[K, V]]: + def entry_transient(self, k: K) -> IMapEntry[K, V] | None: raise NotImplementedError() @@ -767,7 +774,7 @@ def is_empty(self) -> bool: @property @abstractmethod - def first(self) -> Optional[T]: + def first(self) -> T | None: raise NotImplementedError() @property diff --git a/src/basilisp/lang/keyword.py b/src/basilisp/lang/keyword.py index adbedcc2..62941e15 100644 --- a/src/basilisp/lang/keyword.py +++ b/src/basilisp/lang/keyword.py @@ -1,7 +1,6 @@ import threading from collections.abc import Iterable from functools import total_ordering -from typing import Optional, Union from typing_extensions import Unpack @@ -23,7 +22,7 @@ class Keyword(ILispObject, INamed): __slots__ = ("_name", "_ns", "_hash") - def __init__(self, name: str, ns: Optional[str] = None) -> None: + def __init__(self, name: str, ns: str | None = None) -> None: self._name = name self._ns = ns self._hash = hash_kw(name, ns) @@ -33,11 +32,11 @@ def name(self) -> str: return self._name @property - def ns(self) -> Optional[str]: + def ns(self) -> str | None: return self._ns @classmethod - def with_name(cls, name: str, ns: Optional[str] = None) -> "Keyword": + def with_name(cls, name: str, ns: str | None = None) -> "Keyword": return keyword(name, ns=ns) def _lrepr(self, **kwargs: Unpack[PrintSettings]) -> str: @@ -67,7 +66,7 @@ def __lt__(self, other): return False return self._ns < other._ns or self._name < other._name - def __call__(self, m: Union[IAssociative, IPersistentSet], default=None): + def __call__(self, m: IAssociative | IPersistentSet, default=None): if isinstance(m, IPersistentSet): return self if self in m else default try: @@ -81,7 +80,7 @@ def __reduce__(self): def complete( text: str, - kw_cache: Optional[IPersistentMap[int, Keyword]] = None, + kw_cache: IPersistentMap[int, Keyword] | None = None, ) -> Iterable[str]: """Return an iterable of possible completions for the given text.""" assert text.startswith(":") @@ -107,12 +106,12 @@ def complete( return map(str, results) -def hash_kw(name: str, ns: Optional[str] = None) -> int: +def hash_kw(name: str, ns: str | None = None) -> int: """Return the hash of a potential Keyword instance by its name and namespace.""" return hash((name, ns)) -def keyword_from_hash(kw_hash: int, name: str, ns: Optional[str] = None) -> Keyword: +def keyword_from_hash(kw_hash: int, name: str, ns: str | None = None) -> Keyword: """Return the interned keyword with the hash `kw_hash` or create and intern a new keyword with name `name` and optional namespace `ns`. @@ -136,14 +135,14 @@ def keyword_from_hash(kw_hash: int, name: str, ns: Optional[str] = None) -> Keyw return kw -def find_keyword(name: str, ns: Optional[str] = None) -> Optional[Keyword]: +def find_keyword(name: str, ns: str | None = None) -> Keyword | None: """Return the already-interned keyword named by `name` and `ns`, if one exists. If the keyword with that name is not interned, return None.""" with _LOCK: return _INTERN.val_at(hash_kw(name, ns)) -def keyword(name: str, ns: Optional[str] = None) -> Keyword: +def keyword(name: str, ns: str | None = None) -> Keyword: """Return a keyword with name `name` and optional namespace `ns`. Keyword instances are interned, so an existing object may be returned if one diff --git a/src/basilisp/lang/list.py b/src/basilisp/lang/list.py index efc65e1e..bd33fc49 100644 --- a/src/basilisp/lang/list.py +++ b/src/basilisp/lang/list.py @@ -1,4 +1,4 @@ -from typing import Optional, TypeVar, cast +from typing import TypeVar, cast from pyrsistent import PList, plist # noqa # pylint: disable=unused-import from pyrsistent._plist import _EMPTY_PLIST # pylint: disable=import-private-name @@ -42,10 +42,10 @@ def _lrepr(self, **kwargs: Unpack[PrintSettings]) -> str: return _seq_lrepr(self._inner, "(", ")", meta=self._meta, **kwargs) @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentList": + def with_meta(self, meta: IPersistentMap | None) -> "PersistentList": return list(self._inner, meta=meta) @property @@ -74,7 +74,7 @@ def cons(self, *elems: T) -> "PersistentList[T]": def empty(self) -> "PersistentList": return EMPTY.with_meta(self._meta) - def seq(self) -> Optional[ISeq[T]]: + def seq(self) -> ISeq[T] | None: if len(self._inner) == 0: return None return super().seq() diff --git a/src/basilisp/lang/map.py b/src/basilisp/lang/map.py index 2b500b75..1723f546 100644 --- a/src/basilisp/lang/map.py +++ b/src/basilisp/lang/map.py @@ -1,7 +1,7 @@ from builtins import map as pymap -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from itertools import islice -from typing import Any, Callable, Optional, TypeVar, Union, cast +from typing import Any, TypeVar, cast from immutables import Map as _Map from immutables import MapMutation @@ -78,7 +78,7 @@ def dissoc_transient(self, *ks: K) -> "TransientMap[K, V]": pass return self - def entry_transient(self, k: K) -> Optional[IMapEntry[K, V]]: + def entry_transient(self, k: K) -> IMapEntry[K, V] | None: v = self._inner.get(k, cast("V", _ENTRY_SENTINEL)) if v is _ENTRY_SENTINEL: return None @@ -89,12 +89,12 @@ def val_at(self, k, default=None): def cons_transient( # type: ignore[override] self, - *elems: Union[ - IPersistentMap[K, V], - IMapEntry[K, V], - IPersistentVector[Union[K, V]], - Mapping[K, V], - ], + *elems: ( + IPersistentMap[K, V] + | IMapEntry[K, V] + | IPersistentVector[K | V] + | Mapping[K, V] + ), ) -> "TransientMap[K, V]": try: for elem in elems: @@ -123,7 +123,7 @@ def map_lrepr( # pylint: disable=too-many-locals entries: Callable[[], Iterable[tuple[Any, Any]]], start: str, end: str, - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, **kwargs: Unpack[PrintSettings], ) -> str: """Produce a Lisp representation of an associative collection, bookended @@ -220,7 +220,7 @@ class PersistentMap( def __init__( self, m: "_Map[K, V]", - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, ) -> None: self._inner = m self._meta = meta @@ -228,8 +228,8 @@ def __init__( @classmethod def from_coll( cls, - members: Union[Mapping[K, V], Iterable[tuple[K, V]]], - meta: Optional[IPersistentMap] = None, + members: Mapping[K, V] | Iterable[tuple[K, V]], + meta: IPersistentMap | None = None, ) -> "PersistentMap[K, V]": return PersistentMap(_Map(members), meta=meta) @@ -273,10 +273,10 @@ def _lrepr(self, **kwargs: Unpack[PrintSettings]): ) @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentMap": + def with_meta(self, meta: IPersistentMap | None) -> "PersistentMap": return PersistentMap(self._inner, meta=meta) def assoc(self, *kvs): @@ -321,12 +321,12 @@ def update_with( # type: ignore[return] def cons( # type: ignore[override, return] self, - *elems: Union[ - IPersistentMap[K, V], - IMapEntry[K, V], - IPersistentVector[Union[K, V]], - Mapping[K, V], - ], + *elems: ( + IPersistentMap[K, V] + | IMapEntry[K, V] + | IPersistentVector[K | V] + | Mapping[K, V] + ), ) -> "PersistentMap[K, V]": with self._inner.mutate() as m: try: @@ -351,7 +351,7 @@ def cons( # type: ignore[override, return] def empty(self) -> "PersistentMap": return EMPTY.with_meta(self._meta) - def seq(self) -> Optional[ISeq[IMapEntry[K, V]]]: + def seq(self) -> ISeq[IMapEntry[K, V]] | None: if len(self._inner) == 0: return None return iterator_sequence((MapEntry.of(k, v) for k, v in self._inner.items())) @@ -371,7 +371,7 @@ def reduce_kv(self, f: ReduceKVFunction, init: T_reduce) -> T_reduce: def map( # pylint:disable=redefined-builtin - kvs: Mapping[K, V], meta: Optional[IPersistentMap] = None + kvs: Mapping[K, V], meta: IPersistentMap | None = None ) -> PersistentMap[K, V]: """Creates a new map.""" # For some reason, creating a new `immutables.Map` instance from an existing diff --git a/src/basilisp/lang/multifn.py b/src/basilisp/lang/multifn.py index 5c29c4d5..6bcd8c55 100644 --- a/src/basilisp/lang/multifn.py +++ b/src/basilisp/lang/multifn.py @@ -1,5 +1,6 @@ import threading -from typing import Any, Callable, Generic, Optional, TypeVar +from collections.abc import Callable +from typing import Any, Generic, TypeVar from basilisp.lang import map as lmap from basilisp.lang import runtime @@ -35,7 +36,7 @@ def __init__( name: sym.Symbol, dispatch: DispatchFunction, default: T, - hierarchy: Optional[IRef] = None, + hierarchy: IRef | None = None, ) -> None: self._name = name self._default = default @@ -101,11 +102,11 @@ def add_method(self, key: T, method: Method) -> None: self._methods = self._methods.assoc(key, method) self._reset_cache() - def _find_and_cache_method(self, key: T) -> Optional[Method]: + def _find_and_cache_method(self, key: T) -> Method | None: """Find and cache the best method for dispatch value `key`.""" with self._lock: - best_key: Optional[T] = None - best_method: Optional[Method] = None + best_key: T | None = None + best_method: Method | None = None for method_key, method in self._methods.items(): if self._is_a(key, method_key): if best_key is None or self._precedes(method_key, best_key): @@ -125,7 +126,7 @@ def _find_and_cache_method(self, key: T) -> Optional[Method]: return best_method - def get_method(self, key: T) -> Optional[Method]: + def get_method(self, key: T) -> Method | None: """Return the method which would handle this dispatch key or None if no method defined for this key and no default.""" if self._cached_hierarchy != self._hierarchy.deref(): @@ -159,7 +160,7 @@ def prefers(self): """Return a mapping of preferred values to the set of other values.""" return self._prefers - def remove_method(self, key: T) -> Optional[Method]: + def remove_method(self, key: T) -> Method | None: """Remove the method defined for this key and return it.""" with self._lock: method = self._methods.val_at(key, None) diff --git a/src/basilisp/lang/promise.py b/src/basilisp/lang/promise.py index 4af62067..735b0c8f 100644 --- a/src/basilisp/lang/promise.py +++ b/src/basilisp/lang/promise.py @@ -1,5 +1,5 @@ import threading -from typing import Optional, TypeVar +from typing import TypeVar from basilisp.lang.interfaces import IBlockingDeref, IPending @@ -12,7 +12,7 @@ class Promise(IBlockingDeref[T], IPending): def __init__(self) -> None: self._condition = threading.Condition() self._is_delivered = False - self._value: Optional[T] = None + self._value: T | None = None def deliver(self, value: T) -> None: with self._condition: @@ -22,8 +22,8 @@ def deliver(self, value: T) -> None: self._condition.notify_all() def deref( - self, timeout: Optional[float] = None, timeout_val: Optional[T] = None - ) -> Optional[T]: + self, timeout: float | None = None, timeout_val: T | None = None + ) -> T | None: with self._condition: if self._condition.wait_for(lambda: self._is_delivered, timeout=timeout): return self._value diff --git a/src/basilisp/lang/queue.py b/src/basilisp/lang/queue.py index eb7061c2..3f1e3e51 100644 --- a/src/basilisp/lang/queue.py +++ b/src/basilisp/lang/queue.py @@ -1,4 +1,4 @@ -from typing import Optional, TypeVar +from typing import TypeVar from pyrsistent import PDeque, pdeque # noqa # pylint: disable=unused-import from typing_extensions import Unpack @@ -53,10 +53,10 @@ def _lrepr(self, **kwargs: Unpack[PrintSettings]) -> str: return _seq_lrepr(self._inner, "#queue (", ")", meta=self._meta, **kwargs) @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentQueue": + def with_meta(self, meta: IPersistentMap | None) -> "PersistentQueue": return queue(self._inner, meta=meta) def cons(self, *elems: T) -> "PersistentQueue[T]": @@ -76,7 +76,7 @@ def pop(self) -> "PersistentQueue[T]": raise IndexError("Cannot pop an empty queue") return PersistentQueue(self._inner.popleft(), meta=self._meta) - def seq(self) -> Optional[ISeq[T]]: + def seq(self) -> ISeq[T] | None: if len(self._inner) == 0: return None return sequence(self) diff --git a/src/basilisp/lang/reader.py b/src/basilisp/lang/reader.py index ee5587ad..d39f0bde 100644 --- a/src/basilisp/lang/reader.py +++ b/src/basilisp/lang/reader.py @@ -9,13 +9,13 @@ import os import re import uuid -from collections.abc import Collection, Iterable, MutableMapping, Sequence +from collections.abc import Callable, Collection, Iterable, MutableMapping, Sequence from datetime import datetime from fractions import Fraction from itertools import chain from re import Pattern from types import TracebackType -from typing import Any, Callable, NoReturn, Optional, TypeVar, Union, cast +from typing import Any, NoReturn, TypeVar, Union, cast import attr from typing_extensions import Unpack @@ -127,9 +127,9 @@ class Comment: @attr.define(repr=False, str=False) class SyntaxError(Exception): message: str - line: Optional[int] = None - col: Optional[int] = None - filename: Optional[str] = None + line: int | None = None + col: int | None = None + filename: str | None = None def __repr__(self): return ( @@ -138,7 +138,7 @@ def __repr__(self): ) def __str__(self): - keys: dict[str, Union[str, int]] = {} + keys: dict[str, str | int] = {} if self.filename is not None: keys["file"] = self.filename if self.line is not None and self.col is not None: @@ -154,14 +154,14 @@ def __str__(self): @format_exception.register(SyntaxError) def format_syntax_error( # pylint: disable=unused-argument e: SyntaxError, - tp: Optional[type[Exception]] = None, - tb: Optional[TracebackType] = None, - disable_color: Optional[bool] = None, + tp: type[Exception] | None = None, + tb: TracebackType | None = None, + disable_color: bool | None = None, ) -> list[str]: """If `disable_color` is True, no color formatting will be applied to the source code.""" - context_exc: Optional[BaseException] = e.__cause__ + context_exc: BaseException | None = e.__cause__ lines: list[str] = [os.linesep] if context_exc is not None: @@ -225,8 +225,8 @@ def __init__( self, stream: io.TextIOBase, pushback_depth: int = 5, - init_line: Optional[int] = None, - init_column: Optional[int] = None, + init_line: int | None = None, + init_column: int | None = None, ) -> None: """`init_line` and `init_column` refer to where the `stream` starts in the broader context, defaulting to 1 and 0 @@ -245,7 +245,7 @@ def __init__( self._update_loc() @property - def name(self) -> Optional[str]: + def name(self) -> str | None: return getattr(self._stream, "name", None) @property @@ -378,12 +378,12 @@ class ReaderContext: def __init__( # pylint: disable=too-many-arguments self, reader: StreamReader, - resolver: Optional[Resolver] = None, - data_readers: Optional[DataReaders] = None, + resolver: Resolver | None = None, + data_readers: DataReaders | None = None, eof: Any = None, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, - default_data_reader_fn: Optional[DefaultDataReaderFn] = None, + default_data_reader_fn: DefaultDataReaderFn | None = None, ) -> None: self._data_readers = Maybe(data_readers).or_else_get(lmap.EMPTY) self._default_data_reader_fn = Maybe(default_data_reader_fn).or_else_get( @@ -540,8 +540,8 @@ def _compile_feature_vec(form: IPersistentList[tuple[kw.Keyword, ReaderForm]]): return vec.vector(feature_list) def val_at( - self, k: kw.Keyword, default: Optional[ReaderForm] = None - ) -> Optional[ReaderForm]: + self, k: kw.Keyword, default: ReaderForm | None = None + ) -> ReaderForm | None: if k == READER_COND_FORM_KW: return self._form elif k == READER_COND_SPLICING_KW: @@ -555,7 +555,7 @@ def is_splicing(self): def select_feature( self, features: IPersistentSet[kw.Keyword] - ) -> Union[ReaderForm, object]: + ) -> ReaderForm | object: for k, form in self._feature_vec: if k in features: return form @@ -610,8 +610,8 @@ def _consume_whitespace(ctx: ReaderContext) -> str: def _read_namespaced( - ctx: ReaderContext, allowed_suffix: Optional[str] = None -) -> tuple[Optional[str], str]: + ctx: ReaderContext, allowed_suffix: str | None = None +) -> tuple[str | None, str]: """Read a namespaced token (keyword or symbol) from the input stream.""" ns: list[str] = [] name: list[str] = [] @@ -657,7 +657,7 @@ def _read_coll( ctx: ReaderContext, f: Callable[ [Collection[Any]], - Union[llist.PersistentList, lset.PersistentSet, vec.PersistentVector], + llist.PersistentList | lset.PersistentSet | vec.PersistentVector, ], end_char: str, coll_name: str, @@ -771,7 +771,7 @@ def __read_map_elems(ctx: ReaderContext) -> Iterable[RawReaderForm]: def _map_key_processor( - namespace: Optional[str], + namespace: str | None, ) -> Callable[[Any], Any]: """Return a map key processor. @@ -798,9 +798,7 @@ def process_key(k: Any) -> Any: @_with_loc -def _read_map( - ctx: ReaderContext, namespace: Optional[str] = None -) -> lmap.PersistentMap: +def _read_map(ctx: ReaderContext, namespace: str | None = None) -> lmap.PersistentMap: """Return a map from the input stream.""" reader = ctx.reader start = reader.advance() @@ -974,7 +972,7 @@ def _read_str(ctx: ReaderContext, allow_arbitrary_escapes: bool = False) -> str: s.append(char) -def _read_fstr(ctx: ReaderContext) -> Union[str, llist.PersistentList]: +def _read_fstr(ctx: ReaderContext) -> str | llist.PersistentList: """Return a UTF-8 encoded string from the input stream.""" elems: list[LispReaderForm] = [] s: list[str] = [] @@ -1151,7 +1149,7 @@ def _read_meta(ctx: ReaderContext) -> IMeta: assert start == "^" meta = _read_next_consuming_comment(ctx) - meta_map: Optional[lmap.PersistentMap[LispForm, LispForm]] + meta_map: lmap.PersistentMap[LispForm, LispForm] | None if isinstance(meta, sym.Symbol): meta_map = lmap.map({READER_TAG_KW: meta}) elif isinstance(meta, kw.Keyword): @@ -1188,7 +1186,7 @@ def _walk(form, _, outer_f): @_walk.register(IPersistentList) @_walk.register(ISeq) -def _walk_ipersistentlist(form: Union[IPersistentList, ISeq], inner_f, outer_f): +def _walk_ipersistentlist(form: IPersistentList | ISeq, inner_f, outer_f): coll = llist.list(map(inner_f, form)) if isinstance(form, IMeta) and form.meta is not None: coll = coll.with_meta(form.meta) @@ -1238,7 +1236,7 @@ def _read_function(ctx: ReaderContext) -> llist.PersistentList: form = _read_list(ctx) arg_set = set() - def arg_suffix(arg_num: Optional[str]) -> str: + def arg_suffix(arg_num: str | None) -> str: if arg_num is None: return "1" elif arg_num == "&": @@ -1246,7 +1244,7 @@ def arg_suffix(arg_num: Optional[str]) -> str: else: return arg_num - def sym_replacement(arg_num: Optional[str]) -> sym.Symbol: + def sym_replacement(arg_num: str | None) -> sym.Symbol: suffix = arg_suffix(arg_num) if ctx.is_syntax_quoted: suffix = f"{suffix}#" @@ -1630,7 +1628,7 @@ def _read_reader_conditional(ctx: ReaderContext) -> LispReaderForm: def _load_record_or_type( ctx: ReaderContext, s: sym.Symbol, v: LispReaderForm -) -> Union[IRecord, IType]: +) -> IRecord | IType: """Attempt to load the constructor named by `s` and construct a new record or type instance from the vector or map following name.""" assert s.ns is None, "Record reader macro cannot have namespace" @@ -1821,12 +1819,12 @@ def _read_next(ctx: ReaderContext) -> LispReaderForm: # noqa: C901 def syntax_quote( # pylint: disable=too-many-arguments form: RawReaderForm, - resolver: Optional[Resolver] = None, - data_readers: Optional[DataReaders] = None, + resolver: Resolver | None = None, + data_readers: DataReaders | None = None, eof: Any = EOF, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, - default_data_reader_fn: Optional[DefaultDataReaderFn] = None, + default_data_reader_fn: DefaultDataReaderFn | None = None, ): """Return the syntax quoted version of a form.""" # the buffer is unused here, but is necessary to create a ReaderContext @@ -1845,15 +1843,15 @@ def syntax_quote( # pylint: disable=too-many-arguments def read( # pylint: disable=too-many-arguments stream, - resolver: Optional[Resolver] = None, - data_readers: Optional[DataReaders] = None, + resolver: Resolver | None = None, + data_readers: DataReaders | None = None, eof: Any = EOF, is_eof_error: bool = False, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, - default_data_reader_fn: Optional[DefaultDataReaderFn] = None, - init_line: Optional[int] = None, - init_column: Optional[int] = None, + default_data_reader_fn: DefaultDataReaderFn | None = None, + init_line: int | None = None, + init_column: int | None = None, ) -> Iterable[RawReaderForm]: """Read the contents of a stream as a Lisp expression. @@ -1907,15 +1905,15 @@ def read( # pylint: disable=too-many-arguments def read_str( # pylint: disable=too-many-arguments s: str, - resolver: Optional[Resolver] = None, - data_readers: Optional[DataReaders] = None, + resolver: Resolver | None = None, + data_readers: DataReaders | None = None, eof: Any = EOF, is_eof_error: bool = False, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, - default_data_reader_fn: Optional[DefaultDataReaderFn] = None, - init_line: Optional[int] = None, - init_column: Optional[int] = None, + default_data_reader_fn: DefaultDataReaderFn | None = None, + init_line: int | None = None, + init_column: int | None = None, ) -> Iterable[RawReaderForm]: """Read the contents of a string as a Lisp expression. @@ -1942,13 +1940,13 @@ def read_str( # pylint: disable=too-many-arguments def read_file( # pylint: disable=too-many-arguments filename: str, - resolver: Optional[Resolver] = None, - data_readers: Optional[DataReaders] = None, + resolver: Resolver | None = None, + data_readers: DataReaders | None = None, eof: Any = EOF, is_eof_error: bool = False, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, - default_data_reader_fn: Optional[DefaultDataReaderFn] = None, + default_data_reader_fn: DefaultDataReaderFn | None = None, ) -> Iterable[RawReaderForm]: """Read the contents of a file as a Lisp expression. diff --git a/src/basilisp/lang/reference.py b/src/basilisp/lang/reference.py index 476d654f..8b35940e 100644 --- a/src/basilisp/lang/reference.py +++ b/src/basilisp/lang/reference.py @@ -1,7 +1,8 @@ import threading -from typing import Any, Callable, Optional, TypeVar +from collections.abc import Callable +from typing import Any, Concatenate, Optional, TypeVar -from typing_extensions import Concatenate, ParamSpec +from typing_extensions import ParamSpec from basilisp.lang import keyword as kw from basilisp.lang import map as lmap @@ -28,19 +29,19 @@ class ReferenceBase(IReference): Implementers must have the `_lock` and `_meta` properties defined.""" _lock: threading.RLock - _meta: Optional[IPersistentMap] + _meta: IPersistentMap | None @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: with self._lock: return self._meta - def alter_meta(self, f: AlterMeta, *args) -> Optional[IPersistentMap]: + def alter_meta(self, f: AlterMeta, *args) -> IPersistentMap | None: with self._lock: self._meta = f(self._meta, *args) return self._meta - def reset_meta(self, meta: Optional[IPersistentMap]) -> Optional[IPersistentMap]: + def reset_meta(self, meta: IPersistentMap | None) -> IPersistentMap | None: with self._lock: self._meta = meta return meta @@ -59,7 +60,7 @@ class RefBase(IRef[T], ReferenceBase): Implementers must have the `_validators` and `_watches` properties defined. """ - _validator: Optional[RefValidator[T]] + _validator: RefValidator[T] | None _watches: IPersistentMap[RefWatchKey, RefWatcher[T]] def add_watch(self, k: RefWatchKey, wf: RefWatcher[T]) -> "RefBase[T]": @@ -76,16 +77,16 @@ def remove_watch(self, k: RefWatchKey) -> "RefBase[T]": self._watches = self._watches.dissoc(k) return self - def get_validator(self) -> Optional[RefValidator[T]]: + def get_validator(self) -> RefValidator[T] | None: return self._validator - def set_validator(self, vf: Optional[RefValidator[T]] = None) -> None: + def set_validator(self, vf: RefValidator[T] | None = None) -> None: with self._lock: if vf is not None: self._validate(self.deref(), vf=vf) self._validator = vf - def _validate(self, val: Any, vf: Optional[RefValidator[T]] = None) -> None: + def _validate(self, val: Any, vf: RefValidator[T] | None = None) -> None: vf = vf or self._validator if vf is not None: try: diff --git a/src/basilisp/lang/runtime.py b/src/basilisp/lang/runtime.py index 773e33ac..4467c6e4 100644 --- a/src/basilisp/lang/runtime.py +++ b/src/basilisp/lang/runtime.py @@ -17,9 +17,9 @@ import sys import threading import types -from collections.abc import Iterable, Iterator, Mapping, Sequence, Sized +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence, Sized from fractions import Fraction -from typing import AbstractSet, Any, Callable, NoReturn, Optional, TypeVar, Union, cast +from typing import AbstractSet, Any, NoReturn, Optional, TypeVar, Union, cast import attr @@ -245,7 +245,7 @@ def __init__( ns: "Namespace", name: sym.Symbol, dynamic: bool = False, - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, ) -> None: self._ns = ns self._name = name @@ -296,7 +296,7 @@ def set_dynamic(self, dynamic: bool) -> None: self._tl = _VarBindings() if dynamic else None @property - def is_private(self) -> Optional[bool]: + def is_private(self) -> bool | None: if self._meta is not None: return self._meta.val_at(_PRIVATE_META_KEY) return False @@ -388,7 +388,7 @@ def intern( # pylint: disable=too-many-arguments name: sym.Symbol, val, dynamic: bool = False, - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, ) -> "Var": """Intern the value bound to the symbol `name` in namespace `ns`. @@ -415,7 +415,7 @@ def intern_unbound( ns: Union["Namespace", sym.Symbol], name: sym.Symbol, dynamic: bool = False, - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, ) -> "Var": """Create a new unbound `Var` instance to the symbol `name` in namespace `ns`.""" return cls.intern(ns, name, cls.__UNBOUND_SENTINEL, dynamic=dynamic, meta=meta) @@ -591,13 +591,11 @@ class Namespace(ReferenceBase): "_import_refers", ) - def __init__( - self, name: sym.Symbol, module: Optional[BasilispModule] = None - ) -> None: + def __init__(self, name: sym.Symbol, module: BasilispModule | None = None) -> None: self._name = name self._module = Maybe(module).or_else(lambda: _new_module(name.as_python_sym())) - self._meta: Optional[IPersistentMap] = None + self._meta: IPersistentMap | None = None self._lock = threading.RLock() self._aliases: NamespaceMap = lmap.EMPTY @@ -776,7 +774,7 @@ def unmap(self, sym: sym.Symbol) -> None: with self._lock: self._interns = self._interns.dissoc(sym) - def find(self, sym: sym.Symbol) -> Optional[Var]: + def find(self, sym: sym.Symbol) -> Var | None: """Find Vars mapped by the given Symbol input or None if no Vars are mapped by that Symbol.""" with self._lock: @@ -790,7 +788,7 @@ def add_import( sym: sym.Symbol, module: Module, *aliases: sym.Symbol, - refers: Optional[dict[sym.Symbol, Any]] = None, + refers: dict[sym.Symbol, Any] | None = None, ) -> None: """Add the Symbol as an imported Symbol in this Namespace. @@ -817,14 +815,14 @@ def add_import( m = m.assoc(alias, sym) self._import_aliases = m - def get_import_refer(self, sym: sym.Symbol) -> Optional[sym.Symbol]: + def get_import_refer(self, sym: sym.Symbol) -> sym.Symbol | None: """Get the Python module member name referred by Symbol or None if it does not exist.""" with self._lock: refer = self._import_refers.val_at(sym, None) return refer.module_name if refer is not None else None - def get_import(self, sym: sym.Symbol) -> Optional[BasilispModule]: + def get_import(self, sym: sym.Symbol) -> BasilispModule | None: """Return the module if a module named by sym has been imported into this Namespace, None otherwise. @@ -845,7 +843,7 @@ def add_refer(self, sym: sym.Symbol, var: Var) -> None: with self._lock: self._refers = self._refers.assoc(sym, var) - def get_refer(self, sym: sym.Symbol) -> Optional[Var]: + def get_refer(self, sym: sym.Symbol) -> Var | None: """Get the Var referred by Symbol or None if it does not exist.""" with self._lock: return self._refers.val_at(sym, None) @@ -868,7 +866,7 @@ def ns_cache(cls) -> lmap.PersistentMap: def __get_or_create( ns_cache: NamespaceMap, name: sym.Symbol, - module: Optional[BasilispModule] = None, + module: BasilispModule | None = None, ) -> lmap.PersistentMap: """Private swap function used by `get_or_create` to atomically swap the new namespace map into the global cache.""" @@ -893,7 +891,7 @@ def __get_or_create( @classmethod def get_or_create( - cls, name: sym.Symbol, module: Optional[BasilispModule] = None + cls, name: sym.Symbol, module: BasilispModule | None = None ) -> "Namespace": """Get the namespace bound to the symbol `name` in the global namespace cache, creating it if it does not exist. @@ -923,7 +921,7 @@ def remove(cls, name: sym.Symbol) -> Optional["Namespace"]: raise ValueError("Cannot remove the Basilisp core namespace") while True: oldval: lmap.PersistentMap = cls._NAMESPACES.deref() - ns: Optional[Namespace] = oldval.val_at(name, None) + ns: Namespace | None = oldval.val_at(name, None) newval = oldval if ns is not None: newval = oldval.dissoc(name) @@ -943,7 +941,7 @@ def is_match(entry: tuple[sym.Symbol, Any]) -> bool: return is_match def __complete_alias( - self, prefix: str, name_in_ns: Optional[str] = None + self, prefix: str, name_in_ns: str | None = None ) -> Iterable[str]: """Return an iterable of possible completions matching the given prefix from the list of aliased namespaces. If name_in_ns is given, @@ -963,7 +961,7 @@ def __complete_alias( yield f"{alias}/" def __complete_imports_and_aliases( - self, prefix: str, name_in_module: Optional[str] = None + self, prefix: str, name_in_module: str | None = None ) -> Iterable[str]: """Return an iterable of possible completions matching the given prefix from the list of imports and aliased imports. If name_in_module @@ -1208,7 +1206,7 @@ def _first_none(_: None) -> None: @first.register(ISeq) -def _first_iseq(o: ISeq[T]) -> Optional[T]: +def _first_iseq(o: ISeq[T]) -> T | None: return o.first @@ -1246,13 +1244,13 @@ def nthrest(coll, i: int): coll = rest(coll) -def next_(o) -> Optional[ISeq]: +def next_(o) -> ISeq | None: """Calls rest on o. If o returns an empty sequence or None, returns None. Otherwise, returns the elements after the first in o.""" return to_seq(rest(o)) -def nthnext(coll, i: int) -> Optional[ISeq]: +def nthnext(coll, i: int) -> ISeq | None: """Returns the nth next sequence of coll.""" while True: if coll is None: @@ -1309,7 +1307,7 @@ def concat(*seqs: Any) -> ISeq: def internal_reduce( coll: Any, f: ReduceFunction, - init: Union[T_reduce_init, object] = IReduce.REDUCE_SENTINEL, + init: T_reduce_init | object = IReduce.REDUCE_SENTINEL, ) -> T_reduce_init: raise TypeError(f"Type {type(coll)} cannot be reduced") @@ -1317,9 +1315,9 @@ def internal_reduce( @internal_reduce.register(collections.abc.Iterable) @internal_reduce.register(type(None)) def _internal_reduce_iterable( - coll: Optional[Iterable[T]], + coll: Iterable[T] | None, f: ReduceFunction[T_reduce_init, T], - init: Union[T_reduce_init, object] = IReduce.REDUCE_SENTINEL, + init: T_reduce_init | object = IReduce.REDUCE_SENTINEL, ) -> T_reduce_init: s = to_seq(coll) @@ -1345,7 +1343,7 @@ def _internal_reduce_iterable( def _internal_reduce_ireduce( coll: IReduce, f: ReduceFunction[T_reduce_init, T], - init: Union[T_reduce_init, object] = IReduce.REDUCE_SENTINEL, + init: T_reduce_init | object = IReduce.REDUCE_SENTINEL, ) -> T_reduce_init: if init is IReduce.REDUCE_SENTINEL: return coll.reduce(f) @@ -1566,13 +1564,13 @@ def _keys_none(_: None) -> None: @keys.register(collections.abc.Iterable) @keys.register(ISeqable) -def _keys_iterable(o: Union[ISeqable, Iterable]) -> Optional[ISeq]: +def _keys_iterable(o: ISeqable | Iterable) -> ISeq | None: return keys(to_seq(o)) @keys.register(ISeq) -def _keys_iseq(o: ISeq) -> Optional[ISeq]: - def _key_seq(s: ISeq) -> Optional[ISeq]: +def _keys_iseq(o: ISeq) -> ISeq | None: + def _key_seq(s: ISeq) -> ISeq | None: if to_seq(s) is not None: e = s.first if not isinstance(e, IMapEntry): @@ -1586,7 +1584,7 @@ def _key_seq(s: ISeq) -> Optional[ISeq]: @keys.register(collections.abc.Mapping) -def _keys_mapping(o: Mapping) -> Optional[ISeq]: +def _keys_mapping(o: Mapping) -> ISeq | None: return to_seq(o.keys()) @@ -1602,13 +1600,13 @@ def _vals_none(_: None) -> None: @keys.register(collections.abc.Iterable) @vals.register(ISeqable) -def _vals_iterable(o: Union[ISeqable, Iterable]) -> Optional[ISeq]: +def _vals_iterable(o: ISeqable | Iterable) -> ISeq | None: return vals(to_seq(o)) @vals.register(ISeq) -def _vals_iseq(o: ISeq) -> Optional[ISeq]: - def _val_seq(s: ISeq) -> Optional[ISeq]: +def _vals_iseq(o: ISeq) -> ISeq | None: + def _val_seq(s: ISeq) -> ISeq | None: if to_seq(s) is not None: e = s.first if not isinstance(e, IMapEntry): @@ -1622,7 +1620,7 @@ def _val_seq(s: ISeq) -> Optional[ISeq]: @vals.register(collections.abc.Mapping) -def _vals_mapping(o: Mapping) -> Optional[ISeq]: +def _vals_mapping(o: Mapping) -> ISeq | None: return to_seq(o.values()) @@ -1658,8 +1656,8 @@ def _update_signature_for_partial(f: BasilispFunction, num_args: int) -> None: Additionally, partials do not take the meta from the wrapped function, so that value should be cleared and the `with-meta` method should be replaced with a new method.""" - existing_arities: IPersistentSet[Union[kw.Keyword, int]] = f.arities - new_arities: set[Union[kw.Keyword, int]] = set() + existing_arities: IPersistentSet[kw.Keyword | int] = f.arities + new_arities: set[kw.Keyword | int] = set() for arity in existing_arities: if isinstance(arity, kw.Keyword): new_arities.add(arity) @@ -1704,9 +1702,7 @@ def deref(o, timeout_ms=None, timeout_val=None): @deref.register(IBlockingDeref) -def _deref_blocking( - o: IBlockingDeref, timeout_ms: Optional[int] = None, timeout_val=None -): +def _deref_blocking(o: IBlockingDeref, timeout_ms: int | None = None, timeout_val=None): timeout_s = None if timeout_ms is not None: timeout_s = timeout_ms / 1000 if timeout_ms != 0 else 0 @@ -1812,7 +1808,7 @@ def cmp(x, y): return cmp -def sort(coll, f=compare) -> Optional[ISeq]: +def sort(coll, f=compare) -> ISeq | None: """Return a sorted sequence of the elements in coll. If a comparator function f is provided, compare elements in coll using f or use the `compare` fn if not. @@ -1853,7 +1849,7 @@ def __ge__(self, other): return llist.EMPTY -def sort_by(keyfn, coll, cmp=compare) -> Optional[ISeq]: +def sort_by(keyfn, coll, cmp=compare) -> ISeq | None: """Return a sorted sequence of the elements in coll. If a comparator function cmp is provided, compare elements in coll using cmp or use the `compare` fn if not. @@ -1963,7 +1959,7 @@ def _to_py_kw(o: kw.Keyword, keyword_fn: Callable[[kw.Keyword], Any] = _kw_name) @to_py.register(ISeq) @to_py.register(IPersistentVector) def _to_py_list( - o: Union[IPersistentList, ISeq, IPersistentVector], + o: IPersistentList | ISeq | IPersistentVector, keyword_fn: Callable[[kw.Keyword], Any] = _kw_name, ) -> list: return list(map(functools.partial(to_py, keyword_fn=keyword_fn), o)) @@ -2134,7 +2130,7 @@ def decorator(f): return decorator -def _fn_with_meta(f, meta: Optional[lmap.PersistentMap]): +def _fn_with_meta(f, meta: lmap.PersistentMap | None): """Return a new function with the given meta. If the function f already has a meta map, then merge the new meta with the existing meta.""" @@ -2163,7 +2159,7 @@ def wrapped_f(*args, **kwargs): def _basilisp_fn( - arities: tuple[Union[int, kw.Keyword], ...], + arities: tuple[int | kw.Keyword, ...], ) -> Callable[..., BasilispFunction]: """Create a Basilisp function, setting meta and supplying a with_meta method implementation.""" @@ -2269,7 +2265,7 @@ def _load_constant(s: bytes) -> Any: ############################### -def resolve_alias(s: sym.Symbol, ns: Optional[Namespace] = None) -> sym.Symbol: +def resolve_alias(s: sym.Symbol, ns: Namespace | None = None) -> sym.Symbol: """Resolve the aliased symbol in the current namespace.""" if s in _SPECIAL_FORMS: return s @@ -2289,7 +2285,7 @@ def resolve_alias(s: sym.Symbol, ns: Optional[Namespace] = None) -> sym.Symbol: return sym.symbol(s.name, ns=ns.name) -def resolve_var(s: sym.Symbol, ns: Optional[Namespace] = None) -> Optional[Var]: +def resolve_var(s: sym.Symbol, ns: Namespace | None = None) -> Var | None: """Resolve the aliased symbol to a Var from the specified namespace, or the current namespace if none is specified.""" ns_qualified_sym = resolve_alias(s, ns) @@ -2302,7 +2298,7 @@ def resolve_var(s: sym.Symbol, ns: Optional[Namespace] = None) -> Optional[Var]: @contextlib.contextmanager -def bindings(bindings: Optional[Mapping[Var, Any]] = None): +def bindings(bindings: Mapping[Var, Any] | None = None): """Context manager for temporarily changing the value thread-local value for Basilisp dynamic Vars.""" m = lmap.map(bindings or {}) @@ -2321,7 +2317,7 @@ def bindings(bindings: Optional[Mapping[Var, Any]] = None): @contextlib.contextmanager def ns_bindings( - ns_name: str, module: Optional[BasilispModule] = None + ns_name: str, module: BasilispModule | None = None ) -> Iterator[Namespace]: """Context manager for temporarily changing the value of basilisp.core/*ns*.""" symbol = sym.symbol(ns_name) @@ -2360,7 +2356,7 @@ def get_current_ns() -> Namespace: def set_current_ns( ns_name: str, - module: Optional[BasilispModule] = None, + module: BasilispModule | None = None, ) -> Var: """Set the value of the dynamic variable `*ns*` in the current thread.""" symbol = sym.symbol(ns_name) @@ -2380,7 +2376,7 @@ def set_current_ns( def add_generated_python( generated_python: str, - which_ns: Optional[Namespace] = None, + which_ns: Namespace | None = None, ) -> None: """Add generated Python code to a dynamic variable in which_ns.""" if which_ns is None: diff --git a/src/basilisp/lang/seq.py b/src/basilisp/lang/seq.py index 463c3f57..3cbe235d 100644 --- a/src/basilisp/lang/seq.py +++ b/src/basilisp/lang/seq.py @@ -1,7 +1,7 @@ import functools import threading -from collections.abc import Iterable -from typing import Callable, Optional, TypeVar, overload +from collections.abc import Callable, Iterable +from typing import Optional, TypeVar, overload from basilisp.lang.interfaces import ( IPersistentMap, @@ -18,7 +18,7 @@ class _EmptySequence(IWithMeta, ISequential, ISeq[T]): __slots__ = ("_meta",) - def __init__(self, meta: Optional[IPersistentMap] = None): + def __init__(self, meta: IPersistentMap | None = None): self._meta = meta def __repr__(self): @@ -27,14 +27,14 @@ def __repr__(self): def __bool__(self): return True - def seq(self) -> Optional[ISeq[T]]: + def seq(self) -> ISeq[T] | None: return None @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "_EmptySequence[T]": + def with_meta(self, meta: IPersistentMap | None) -> "_EmptySequence[T]": return _EmptySequence(meta=meta) @property @@ -42,7 +42,7 @@ def is_empty(self) -> bool: return True @property - def first(self) -> Optional[T]: + def first(self) -> T | None: return None @property @@ -68,8 +68,8 @@ class Cons(ISeq[T], ISequential, IWithMeta): def __init__( self, first: T, - seq: Optional[ISeq[T]] = None, - meta: Optional[IPersistentMap] = None, + seq: ISeq[T] | None = None, + meta: IPersistentMap | None = None, ) -> None: self._first = first self._rest = Maybe(seq).or_else_get(EMPTY) @@ -80,7 +80,7 @@ def is_empty(self) -> bool: return False @property - def first(self) -> Optional[T]: + def first(self) -> T | None: return self._first @property @@ -97,10 +97,10 @@ def empty(self): return EMPTY @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "Cons[T]": + def with_meta(self, meta: IPersistentMap | None) -> "Cons[T]": return Cons(self._first, seq=self._rest, meta=meta) @@ -119,22 +119,22 @@ class LazySeq(IWithMeta, ISequential, ISeq[T]): def __init__( self, - gen: Optional[LazySeqGenerator], - seq: Optional[ISeq[T]] = None, + gen: LazySeqGenerator | None, + seq: ISeq[T] | None = None, *, - meta: Optional[IPersistentMap] = None, + meta: IPersistentMap | None = None, ) -> None: - self._gen: Optional[LazySeqGenerator] = gen - self._obj: Optional[ISeq[T]] = None - self._seq: Optional[ISeq[T]] = seq + self._gen: LazySeqGenerator | None = gen + self._obj: ISeq[T] | None = None + self._seq: ISeq[T] | None = seq self._lock = threading.RLock() self._meta = meta @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "LazySeq[T]": + def with_meta(self, meta: IPersistentMap | None) -> "LazySeq[T]": return LazySeq(None, seq=self.seq(), meta=meta) # LazySeqs have a fairly complex inner state, in spite of the simple interface. @@ -146,7 +146,7 @@ def with_meta(self, meta: Optional[IPersistentMap]) -> "LazySeq[T]": # LazySeq objects before calling `(seq ...)` on the result, which is cached in the # _seq attribute. - def _compute_seq(self) -> Optional[ISeq[T]]: + def _compute_seq(self) -> ISeq[T] | None: if self._gen is not None: # This local caching of the generator function and clearing of self._gen # is absolutely critical for supporting co-recursive lazy sequences. @@ -168,7 +168,7 @@ def _compute_seq(self) -> Optional[ISeq[T]]: self._obj = gen() return self._obj if self._obj is not None else self._seq - def seq(self) -> Optional[ISeq[T]]: + def seq(self) -> ISeq[T] | None: with self._lock: self._compute_seq() if self._obj is not None: @@ -192,7 +192,7 @@ def is_empty(self) -> bool: return self.seq() is None @property - def first(self) -> Optional[T]: + def first(self) -> T | None: if self.is_empty: return None return self.seq().first # type: ignore[union-attr] @@ -253,7 +253,7 @@ def _seq_or_nil(s: None) -> None: ... @overload -def _seq_or_nil(s: ISeq) -> Optional[ISeq]: ... +def _seq_or_nil(s: ISeq) -> ISeq | None: ... def _seq_or_nil(s): @@ -264,7 +264,7 @@ def _seq_or_nil(s): @functools.singledispatch -def to_seq(o) -> Optional[ISeq]: +def to_seq(o) -> ISeq | None: """Coerce the argument o to a ISeq. If o is None, return None.""" return _seq_or_nil(sequence(o)) @@ -275,16 +275,16 @@ def _to_seq_none(_) -> None: @to_seq.register(ISeq) -def _to_seq_iseq(o: ISeq) -> Optional[ISeq]: +def _to_seq_iseq(o: ISeq) -> ISeq | None: return _seq_or_nil(o) @to_seq.register(LazySeq) -def _to_seq_lazyseq(o: LazySeq) -> Optional[ISeq]: +def _to_seq_lazyseq(o: LazySeq) -> ISeq | None: # Force evaluation of the LazySeq by calling o.seq() directly. return o.seq() @to_seq.register(ISeqable) -def _to_seq_iseqable(o: ISeqable) -> Optional[ISeq]: +def _to_seq_iseqable(o: ISeqable) -> ISeq | None: return _seq_or_nil(o.seq()) diff --git a/src/basilisp/lang/set.py b/src/basilisp/lang/set.py index 8029d5b0..fe15a298 100644 --- a/src/basilisp/lang/set.py +++ b/src/basilisp/lang/set.py @@ -1,6 +1,6 @@ from collections.abc import Iterable from collections.abc import Set as _PySet -from typing import AbstractSet, Optional, TypeVar +from typing import AbstractSet, TypeVar from immutables import Map as _Map from immutables import MapMutation @@ -75,13 +75,13 @@ class PersistentSet( __slots__ = ("_inner", "_meta") - def __init__(self, m: "_Map[T, T]", meta: Optional[IPersistentMap] = None) -> None: + def __init__(self, m: "_Map[T, T]", meta: IPersistentMap | None = None) -> None: self._inner = m self._meta = meta @classmethod def from_iterable( - cls, members: Optional[Iterable[T]], meta: Optional[IPersistentMap] = None + cls, members: Iterable[T] | None, meta: IPersistentMap | None = None ) -> "PersistentSet": return PersistentSet(_Map((m, m) for m in (members or ())), meta=meta) @@ -145,10 +145,10 @@ def union(self, *others): return e @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentSet[T]": + def with_meta(self, meta: IPersistentMap | None) -> "PersistentSet[T]": return set(self._inner, meta=meta) def cons(self, *elems: T) -> "PersistentSet[T]": # type: ignore[return] @@ -169,7 +169,7 @@ def disj(self, *elems: T) -> "PersistentSet[T]": # type: ignore[return] def empty(self) -> "PersistentSet": return EMPTY.with_meta(self._meta) - def seq(self) -> Optional[ISeq[T]]: + def seq(self) -> ISeq[T] | None: if len(self._inner) == 0: return None return sequence(self) @@ -182,12 +182,12 @@ def to_transient(self) -> TransientSet: def set( # pylint:disable=redefined-builtin - members: Iterable[T], meta: Optional[IPersistentMap] = None + members: Iterable[T], meta: IPersistentMap | None = None ) -> PersistentSet[T]: """Creates a new set.""" return PersistentSet.from_iterable(members, meta=meta) -def s(*members: T, meta: Optional[IPersistentMap] = None) -> PersistentSet[T]: +def s(*members: T, meta: IPersistentMap | None = None) -> PersistentSet[T]: """Creates a new set from members.""" return PersistentSet.from_iterable(members, meta=meta) diff --git a/src/basilisp/lang/source.py b/src/basilisp/lang/source.py index 0de16136..e779e90a 100644 --- a/src/basilisp/lang/source.py +++ b/src/basilisp/lang/source.py @@ -2,7 +2,6 @@ import linecache import os from collections.abc import Iterable -from typing import Optional try: import pygments.formatters @@ -11,15 +10,15 @@ except ImportError: # pragma: no cover def _format_source( - s: str, disable_color: Optional[bool] = None # pylint: disable=unused-argument + s: str, disable_color: bool | None = None # pylint: disable=unused-argument ) -> str: return f"{s}{os.linesep}" else: def _get_formatter_name( - disable_color: Optional[bool] = None, - ) -> Optional[str]: # pragma: no cover + disable_color: bool | None = None, + ) -> str | None: # pragma: no cover """Get the Pygments formatter name for formatting the source code by inspecting various environment variables set by terminals. @@ -37,7 +36,7 @@ def _get_formatter_name( return "terminal" def _format_source( - s: str, disable_color: Optional[bool] = None + s: str, disable_color: bool | None = None ) -> str: # pragma: no cover """Format source code for terminal output. @@ -56,10 +55,10 @@ def _format_source( def format_source_context( # pylint: disable=too-many-arguments,too-many-locals filename: str, line: int, - end_line: Optional[int] = None, + end_line: int | None = None, num_context_lines: int = 5, show_cause_marker: bool = True, - disable_color: Optional[bool] = None, + disable_color: bool | None = None, ) -> list[str]: """Format source code context with line numbers and identifiers for the affected line(s). @@ -71,7 +70,7 @@ def format_source_context( # pylint: disable=too-many-arguments,too-many-locals lines = [] if not filename.startswith("<") and not filename.endswith(">"): - cause_range: Optional[range] + cause_range: range | None if not show_cause_marker: cause_range = None elif end_line is not None and end_line != line: diff --git a/src/basilisp/lang/symbol.py b/src/basilisp/lang/symbol.py index 8dfe0223..d0a0d56e 100644 --- a/src/basilisp/lang/symbol.py +++ b/src/basilisp/lang/symbol.py @@ -1,5 +1,4 @@ from functools import total_ordering -from typing import Optional, Union from typing_extensions import Unpack @@ -20,7 +19,7 @@ class Symbol(ILispObject, INamed, IWithMeta): __slots__ = ("_name", "_ns", "_meta", "_hash") def __init__( - self, name: str, ns: Optional[str] = None, meta: Optional[IPersistentMap] = None + self, name: str, ns: str | None = None, meta: IPersistentMap | None = None ) -> None: self._name = name self._ns = ns @@ -44,18 +43,18 @@ def name(self) -> str: return self._name @property - def ns(self) -> Optional[str]: + def ns(self) -> str | None: return self._ns @classmethod - def with_name(cls, name: str, ns: Optional[str] = None) -> "Symbol": + def with_name(cls, name: str, ns: str | None = None) -> "Symbol": return Symbol(name, ns=ns) @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "Symbol": + def with_meta(self, meta: IPersistentMap | None) -> "Symbol": return Symbol(self._name, self._ns, meta=meta) def as_python_sym(self) -> str: @@ -84,7 +83,7 @@ def __lt__(self, other): return False return self._ns < other._ns or self._name < other._name - def __call__(self, m: Union[IAssociative, IPersistentSet], default=None): + def __call__(self, m: IAssociative | IPersistentSet, default=None): if isinstance(m, IPersistentSet): return self if self in m else default try: @@ -94,7 +93,7 @@ def __call__(self, m: Union[IAssociative, IPersistentSet], default=None): def symbol( - name: str, ns: Optional[str] = None, meta: Optional[IPersistentMap] = None + name: str, ns: str | None = None, meta: IPersistentMap | None = None ) -> Symbol: """Create a new symbol.""" return Symbol(name, ns=ns, meta=meta) diff --git a/src/basilisp/lang/tagged.py b/src/basilisp/lang/tagged.py index 9237368e..05d807d9 100644 --- a/src/basilisp/lang/tagged.py +++ b/src/basilisp/lang/tagged.py @@ -1,4 +1,4 @@ -from typing import Optional, TypeVar, Union +from typing import TypeVar, Union from typing_extensions import Unpack @@ -23,7 +23,7 @@ class TaggedLiteral(ILispObject, ILookup[K, T]): def __init__(self, tag: Symbol, form) -> None: self._tag = tag self._form = form - self._hash: Optional[int] = None + self._hash: int | None = None @property def tag(self) -> Symbol: @@ -51,7 +51,7 @@ def __hash__(self): def __getitem__(self, item): return self.val_at(item) - def val_at(self, k: K, default: Optional[V] = None) -> T: + def val_at(self, k: K, default: V | None = None) -> T: if k == _TAG_KW: return self._tag elif k == _FORM_KW: diff --git a/src/basilisp/lang/typing.py b/src/basilisp/lang/typing.py index ab1629e2..df423650 100644 --- a/src/basilisp/lang/typing.py +++ b/src/basilisp/lang/typing.py @@ -3,7 +3,7 @@ from decimal import Decimal from fractions import Fraction from re import Pattern -from typing import Optional, Protocol, Union +from typing import Protocol, Union from basilisp.lang import keyword as kw from basilisp.lang import list as llist @@ -55,9 +55,9 @@ class BasilispFunction(Protocol): _basilisp_fn: bool - arities: IPersistentSet[Union[kw.Keyword, int]] - meta: Optional[IPersistentMap] + arities: IPersistentSet[kw.Keyword | int] + meta: IPersistentMap | None def __call__(self, *args, **kwargs): ... - def with_meta(self, meta: Optional[IPersistentMap]) -> "BasilispFunction": ... + def with_meta(self, meta: IPersistentMap | None) -> "BasilispFunction": ... diff --git a/src/basilisp/lang/vector.py b/src/basilisp/lang/vector.py index 45ca65c0..5809f767 100644 --- a/src/basilisp/lang/vector.py +++ b/src/basilisp/lang/vector.py @@ -1,6 +1,6 @@ from collections.abc import Iterable, Sequence from functools import total_ordering -from typing import Optional, TypeVar, Union, cast, overload +from typing import TypeVar, Union, cast, overload from pyrsistent import PVector, pvector # noqa # pylint: disable=unused-import from pyrsistent.typing import PVectorEvolver @@ -64,7 +64,7 @@ def assoc_transient(self, *kvs: T) -> "TransientVector[T]": def contains_transient(self, k: int) -> bool: return 0 <= k < len(self._inner) - def entry_transient(self, k: int) -> Optional[IMapEntry[int, T]]: + def entry_transient(self, k: int) -> IMapEntry[int, T] | None: try: return MapEntry.of(k, self._inner[k]) except IndexError: @@ -102,7 +102,7 @@ class PersistentVector( __slots__ = ("_inner", "_meta") def __init__( - self, wrapped: "PVector[T]", meta: Optional[IPersistentMap] = None + self, wrapped: "PVector[T]", meta: IPersistentMap | None = None ) -> None: self._inner = wrapped self._meta = meta @@ -134,7 +134,7 @@ def __iter__(self): def __len__(self): return len(self._inner) - def __call__(self, k: int, default: Optional[T] = None) -> Optional[T]: + def __call__(self, k: int, default: T | None = None) -> T | None: return self.val_at(k, default=default) def __lt__(self, other): @@ -164,10 +164,10 @@ def _lrepr(self, **kwargs: Unpack[PrintSettings]) -> str: return _seq_lrepr(self._inner, "[", "]", meta=self._meta, **kwargs) @property - def meta(self) -> Optional[IPersistentMap]: + def meta(self) -> IPersistentMap | None: return self._meta - def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentVector[T]": + def with_meta(self, meta: IPersistentMap | None) -> "PersistentVector[T]": return vector(self._inner, meta=meta) def cons(self, *elems: T) -> "PersistentVector[T]": # type: ignore[override] @@ -182,13 +182,13 @@ def assoc(self, *kvs: T) -> "PersistentVector[T]": def contains(self, k: int) -> bool: return 0 <= k < len(self._inner) - def entry(self, k: int) -> Optional[IMapEntry[int, T]]: + def entry(self, k: int) -> IMapEntry[int, T] | None: try: return MapEntry.of(k, self._inner[k]) except IndexError: return None - def val_at(self, k: int, default: Optional[T] = None) -> Optional[T]: + def val_at(self, k: int, default: T | None = None) -> T | None: try: return self._inner[k] except (IndexError, TypeError): @@ -197,12 +197,12 @@ def val_at(self, k: int, default: Optional[T] = None) -> Optional[T]: def empty(self) -> "PersistentVector[T]": return EMPTY.with_meta(self._meta) - def seq(self) -> Optional[ISeq[T]]: # type: ignore[override] + def seq(self) -> ISeq[T] | None: # type: ignore[override] if len(self._inner) == 0: return None return sequence(self) - def peek(self) -> Optional[T]: + def peek(self) -> T | None: if len(self) == 0: return None return self[-1] @@ -280,7 +280,7 @@ def of(k: K, v: V) -> "MapEntry[K, V]": return MapEntry(pvector([k, v])) @staticmethod - def from_vec(v: Sequence[Union[K, V]]) -> "MapEntry[K, V]": + def from_vec(v: Sequence[K | V]) -> "MapEntry[K, V]": return MapEntry(pvector(v)) @@ -288,12 +288,12 @@ def from_vec(v: Sequence[Union[K, V]]) -> "MapEntry[K, V]": def vector( - members: Iterable[T], meta: Optional[IPersistentMap] = None + members: Iterable[T], meta: IPersistentMap | None = None ) -> PersistentVector[T]: """Creates a new vector.""" return PersistentVector(pvector(members), meta=meta) -def v(*members: T, meta: Optional[IPersistentMap] = None) -> PersistentVector[T]: +def v(*members: T, meta: IPersistentMap | None = None) -> PersistentVector[T]: """Creates a new vector from members.""" return PersistentVector(pvector(members), meta=meta) diff --git a/src/basilisp/lang/volatile.py b/src/basilisp/lang/volatile.py index 858abfba..178af5f6 100644 --- a/src/basilisp/lang/volatile.py +++ b/src/basilisp/lang/volatile.py @@ -1,7 +1,8 @@ -from typing import Callable, Optional, TypeVar +from collections.abc import Callable +from typing import Concatenate, TypeVar import attr -from typing_extensions import Concatenate, ParamSpec +from typing_extensions import ParamSpec from basilisp.lang.interfaces import IDeref @@ -17,7 +18,7 @@ class Volatile(IDeref[T]): value: T - def deref(self) -> Optional[T]: + def deref(self) -> T | None: return self.value def reset(self, v: T) -> T: diff --git a/src/basilisp/logconfig.py b/src/basilisp/logconfig.py index 8b6350dd..f7f31c73 100644 --- a/src/basilisp/logconfig.py +++ b/src/basilisp/logconfig.py @@ -1,6 +1,5 @@ import logging import os -from typing import Optional TRACE = 5 @@ -17,9 +16,7 @@ def get_level() -> str: return os.getenv("BASILISP_LOGGING_LEVEL", "WARNING") -def get_handler( - level: Optional[str] = None, fmt: str = DEFAULT_FORMAT -) -> logging.Handler: +def get_handler(level: str | None = None, fmt: str = DEFAULT_FORMAT) -> logging.Handler: """Get the default logging handler for Basilisp.""" handler = ( logging.StreamHandler() @@ -31,9 +28,7 @@ def get_handler( return handler -def configure_root_logger( - level: Optional[str] = None, fmt: str = DEFAULT_FORMAT -) -> None: +def configure_root_logger(level: str | None = None, fmt: str = DEFAULT_FORMAT) -> None: """Configure the Basilisp root logger.""" level = level or get_level() logger = logging.getLogger("basilisp") diff --git a/src/basilisp/main.py b/src/basilisp/main.py index 542d8560..e36f28a1 100644 --- a/src/basilisp/main.py +++ b/src/basilisp/main.py @@ -3,7 +3,6 @@ import sysconfig import threading from pathlib import Path -from typing import Optional from basilisp import importer as importer from basilisp import logconfig @@ -16,7 +15,7 @@ _runtime_is_initialized = False -def init(opts: Optional[CompilerOpts] = None, force_reload: bool = False) -> None: +def init(opts: CompilerOpts | None = None, force_reload: bool = False) -> None: """ Initialize the runtime environment for Basilisp code evaluation. @@ -45,7 +44,7 @@ def init(opts: Optional[CompilerOpts] = None, force_reload: bool = False) -> Non def bootstrap( - target: str, opts: Optional[CompilerOpts] = None + target: str, opts: CompilerOpts | None = None ) -> None: # pragma: no cover """ Import a Basilisp namespace or function identified by ``target``. If a function @@ -71,7 +70,7 @@ def bootstrap( getattr(mod, fn_name)() -def bootstrap_python(site_packages: Optional[str] = None) -> str: +def bootstrap_python(site_packages: str | None = None) -> str: """Bootstrap a Python installation by installing a ``.pth`` file in ``site-packages`` directory (corresponding to "purelib" in :external:py:func:`sysconfig.get_paths`). Returns the path to the @@ -91,7 +90,7 @@ def bootstrap_python(site_packages: Optional[str] = None) -> str: return str(pth) -def unbootstrap_python(site_packages: Optional[str] = None) -> Optional[str]: +def unbootstrap_python(site_packages: str | None = None) -> str | None: """Remove the `basilispbootstrap.pth` file found in the Python site-packages directory (corresponding to "purelib" in :external:py:func:`sysconfig.get_paths`). Return the path of the removed file, if any.""" diff --git a/src/basilisp/util.py b/src/basilisp/util.py index 7710321e..a88a6ad7 100644 --- a/src/basilisp/util.py +++ b/src/basilisp/util.py @@ -1,11 +1,11 @@ import contextlib import time -from collections.abc import Iterable, Sequence -from typing import Callable, Generic, Optional, TypeVar +from collections.abc import Callable, Iterable, Sequence +from typing import Generic, TypeVar @contextlib.contextmanager -def timed(f: Optional[Callable[[int], None]] = None): +def timed(f: Callable[[int], None] | None = None): """Time the execution of code in the with-block, calling the function f (if it is given) with the resulting time in nanoseconds.""" start = time.perf_counter() @@ -23,7 +23,7 @@ def timed(f: Optional[Callable[[int], None]] = None): class Maybe(Generic[T]): __slots__ = ("_inner",) - def __init__(self, inner: Optional[T]) -> None: + def __init__(self, inner: T | None) -> None: self._inner = inner def __eq__(self, other): @@ -58,7 +58,7 @@ def map(self, f: Callable[[T], U]) -> "Maybe[U]": return Maybe(f(self._inner)) @property - def value(self) -> Optional[T]: + def value(self) -> T | None: return self._inner @property diff --git a/tests/basilisp/cli_test.py b/tests/basilisp/cli_test.py index 53a04bf9..9975a549 100644 --- a/tests/basilisp/cli_test.py +++ b/tests/basilisp/cli_test.py @@ -13,7 +13,6 @@ import venv from collections.abc import Sequence from threading import Thread -from typing import Optional from unittest.mock import patch import attr @@ -82,7 +81,7 @@ class CapturedIO: @pytest.fixture def run_cli(monkeypatch, capsys, cap_lisp_io): - def _run_cli(args: Sequence[str], input: Optional[str] = None): + def _run_cli(args: Sequence[str], input: str | None = None): monkeypatch.setattr("basilisp.main._runtime_is_initialized", False) if input is not None: monkeypatch.setattr( @@ -333,7 +332,7 @@ def test_repl_include_extra_path( ["repl", *temp_path_args], input=" ".join( [ - f"(import pathlib sys)", + "(import pathlib sys)", "(doseq [path sys/path]", " (prn (.as-posix (pathlib/Path path))))", ] @@ -413,7 +412,7 @@ def test_run_code_include_extra_path( "-c", os.linesep.join( [ - f"(import pathlib sys)", + "(import pathlib sys)", "(doseq [path sys/path]", " (prn (.as-posix (pathlib/Path path))))", ] @@ -731,7 +730,7 @@ def test_run_stdin_include_extra_path( ["run", *temp_path_args, "-"], input=os.linesep.join( [ - f"(import pathlib sys)", + "(import pathlib sys)", "(doseq [path sys/path]", " (prn (.as-posix (pathlib/Path path))))", ] diff --git a/tests/basilisp/compiler_test.py b/tests/basilisp/compiler_test.py index be2b8d56..bd6a848d 100644 --- a/tests/basilisp/compiler_test.py +++ b/tests/basilisp/compiler_test.py @@ -75,9 +75,9 @@ def _assert_no_logs() -> None: @pytest.fixture def assert_matching_logs( caplog, -) -> typing.Callable[[str, int, typing.Union[typing.Pattern, str]], None]: +) -> typing.Callable[[str, int, typing.Pattern | str], None]: def _assert_matching_logs( - logger_name: str, log_level: int, pattern: typing.Union[typing.Pattern, str] + logger_name: str, log_level: int, pattern: typing.Pattern | str ) -> None: if isinstance(pattern, str): pattern = re.compile(pattern) @@ -106,9 +106,9 @@ def _assert_matching_logs( @pytest.fixture def assert_no_matching_logs( caplog, -) -> typing.Callable[[str, int, typing.Union[typing.Pattern, str]], None]: +) -> typing.Callable[[str, int, typing.Pattern | str], None]: def _assert_no_matching_logs( - logger_name: str, log_level: int, pattern: typing.Union[typing.Pattern, str] + logger_name: str, log_level: int, pattern: typing.Pattern | str ) -> None: if isinstance(pattern, str): pattern = re.compile(pattern) diff --git a/tests/basilisp/conftest.py b/tests/basilisp/conftest.py index b1bc6eca..fa1d9fff 100644 --- a/tests/basilisp/conftest.py +++ b/tests/basilisp/conftest.py @@ -1,6 +1,5 @@ import io import sys -from typing import Dict, Optional, Tuple import pytest @@ -48,8 +47,8 @@ def ns(test_ns: str, test_ns_sym: sym.Symbol) -> runtime.Namespace: def lcompile(ns: runtime.Namespace, compiler_file_path: str) -> CompileFn: def _lcompile( s: str, - resolver: Optional[reader.Resolver] = None, - opts: Optional[dict[str, bool]] = None, + resolver: reader.Resolver | None = None, + opts: dict[str, bool] | None = None, ): """Compile and execute the code in the input string. diff --git a/tests/basilisp/helpers.py b/tests/basilisp/helpers.py index 77743cc1..376b7896 100644 --- a/tests/basilisp/helpers.py +++ b/tests/basilisp/helpers.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, Tuple +from collections.abc import Callable +from typing import Any from basilisp.lang import symbol as sym from basilisp.lang.runtime import CORE_NS_SYM, Namespace diff --git a/tests/basilisp/importer_test.py b/tests/basilisp/importer_test.py index ec87e337..02339aec 100644 --- a/tests/basilisp/importer_test.py +++ b/tests/basilisp/importer_test.py @@ -8,12 +8,10 @@ import tempfile from multiprocessing import Process, get_start_method from tempfile import TemporaryDirectory -from typing import Optional from unittest.mock import patch import pytest -import basilisp.main from basilisp import importer as importer from basilisp.lang import runtime as runtime from basilisp.lang import symbol as sym @@ -119,7 +117,7 @@ def make_new_module(self, module_dir): filenames = set() def _make_new_module( - *ns_path: str, ns_name: str = "", module_text: Optional[str] = None + *ns_path: str, ns_name: str = "", module_text: str | None = None ) -> None: """Generate a new module. If ns_name is not the empty string, use that name as the name of a Basilisp namespace with a single Var named `val` diff --git a/tests/basilisp/prompt_test.py b/tests/basilisp/prompt_test.py index 782b1fbd..699ea606 100644 --- a/tests/basilisp/prompt_test.py +++ b/tests/basilisp/prompt_test.py @@ -1,5 +1,4 @@ -from collections.abc import Iterable -from typing import Callable +from collections.abc import Callable, Iterable from unittest.mock import MagicMock, patch import pytest diff --git a/tests/basilisp/reader_test.py b/tests/basilisp/reader_test.py index fff7b793..9e9ea1d4 100644 --- a/tests/basilisp/reader_test.py +++ b/tests/basilisp/reader_test.py @@ -7,7 +7,6 @@ import uuid from fractions import Fraction from pathlib import Path -from typing import Optional import pytest @@ -37,7 +36,7 @@ def read_str_first( resolver: reader.Resolver = None, data_readers=None, is_eof_error: bool = False, - features: Optional[IPersistentSet[kw.Keyword]] = None, + features: IPersistentSet[kw.Keyword] | None = None, process_reader_cond: bool = True, default_data_reader_fn=None, ):