Skip to content

Implement every planned transforms #4

Description

@AlphaKR93

Implement every transforms planned in src/terser/_pipeline/transforms/README.md.

  • [TODO] Separate terser_hints package (use monorepo)
  • [TODO] Create a new example package to test transforms

Flags:

  • REQUIRES_IMPORT_RESOLVE: Name resolving/binding must be performed first.
  • REQUIRES_MODULE_RESOLVE: Module linking must be performed first.
  • INFLUENCES_MANGLING: May affect the operation of name mangling; will performed after mangling.

Transforms

  • Contracts (REQUIRES_IMPORT_RESOLVE)
    Apply contracts with syntax: <function_def> -> <transform>. Similar to JetBrains' Code contract annotations.
    Default contracts:

    • typing.cast(_, value) -> value (e.g., func_ = cast("Callable", func)func_ = func)
    • typing.assert_never(_) -> None (e.g., assert_never(unreachable)pass)
    • typing.assert_type(value, _) -> value (e.g., d = assert_type(obj, dict)d=obj)
    • terser_hints.not_none(value) -> value (e.g., t = not_none(optional_t)t=optional_t)
  • InlineIIFE (REQUIRES_IMPORT_RESOLVE)
    Inline Immediately-Invoked Function Expressions (@lambda _: _())

    Examples

    Original:

    from terser_hints import constant
    
    @constant
    def some_function():
      foo = 0
      def __inc():
        nonlocal foo; foo += 1
        return foo
      return __inc
    
    class Bar:
      @constant
      @staticmethod
      def some_method():
        bar = 1
        def __mul():
          nonlocal bar; bar *= 16
          return bar
        return __mul

    Minified:

    _some_function__foo=0
    def some_function():
      # Indented intentionally for readability
      global _some_function__foo
      _some_function__foo+=1
      return _some_function__foo
    
    class Bar:
      _some_method__bar=1
      @staticmethod
      def some_method():
        # Indented intentionally for readability
        Bar._some_method__bar<<4
        return Bar._some_method__bar
  • RemoveDummyAssignments (REQUIRES_IMPORT_RESOLVE)
    Remove assignments to oneself (x = x, same binding on both side) or assignments to make the type checker happy (_ = some_method_w_return())

  • RemoveLiteralStatements
    Remove expressions that are just a literal constant.
    CHANGED BEHAVIOR: Docstrings are no longer handled in this transform. (Moved to a separate transform)

  • RemoveDocstrings (REQUIRES_IMPORT_RESOLVE)
    When True, remove docstrings that have not been preserved. The removal of module docstrings is determined by --also-modules.

    • REQUIRES_IMPORT_RESOLVE — due to the mark decorator
  • RemoveAnnotations (REQUIRES_IMPORT_RESOLVE)
    Remove type annotations.
    CHANGED BEHAVIOR:

    • typing.Annotated will not be removed regardless of the option.
    • Quoted annotations (foo: "Foo") are always removed without evaluation.
  • RemoveTypeStatements
    Drop type X = ... (PEP695) type alias statements.

  • RemoveTypingClass (REQUIRES_IMPORT_RESOLVE)
    Remove bare typing.Protocol-based classes (unless decorated with @typing.runtime_checkable) and typing.TypedDict-based classes (converted to dict)

  • RemoveGenerics (REQUIRES_IMPORT_RESOLVE)
    Strip generic [T] type aliases (PEP695) from function/class definitions.

  • RemoveOverloads (REQUIRES_IMPORT_RESOLVE)
    Drop @typing.overload-decorated stub defines. Always True when RemoveTypingDecorators is True.

  • RemoveTypingDecorators (REQUIRES_IMPORT_RESOLVE)
    Strip @typing.override, @typing.final.

  • RemoveExplicitReturnNone
    Convert return None to bare return and drops trailing return/return None from a function body.

  • RemoveExplicitBaseClass
    Remove unnecessary base/meta classes. Currently only removes object from a class's bases.

  • RemoveExceptionBrackets (REQUIRES_IMPORT_RESOLVE)
    Remove empty brackets from built-in exception constructors (raise RuntimeError()raise RuntimeError)
    CHANGED BEHAVIOR: now transform-based.

  • FoldConstants
    Fold constant by evaluating them.

    • Constant arithmetic/unary operations on literals: UNIT_D = 60 * 60 * 24UNIT_D=86400, INT_MAX_VALUE = 2 << 31 - 1INT_MAX_VALUE=2147483647
    • bool-identity comparisons: x == True/x is Truex, x == False/x is Falsenot x (where x is not None)
    • Collection constructors: list()[], dict(){}, tuple()(), ("some", "values")"some","values", set((1, 2)){1,2}
  • RemoveDeadBlocks (runs after FoldConstants)
    Collapse if <literal>: <body> and <body> if <literal> else <other> into just the taken branch.

  • ConvertEarlyExits

    • Invert the condition and/or inline if there's an escape keyword in the else or elif body.
    • Merge if <condition>: return a immediately followed by return b into return a if <condition> else b
  • ConvertDynamicAttributes (REQUIRES_IMPORT_RESOLVE)
    Convert getattr/setattr call into bare access/assignment (getattr(obj, "name")obj.name, setattr(obj, "name", value)obj.name=value)
    name should be a constant literal and a valid keyword identifier.
    Ignored when getattr is called with a default value (3-arg form).

  • ConvertToInline
    Convert conditions with a single-statement body into inline conditions. (if cond: func(x)cond and func(x), if foo: bar(); else: baz()bar() if foo else baz())

  • ConvertToLambda
    Convert functions with a single-return body into lambdas. (def func(...): return exprfunc=lambda ...:expr)

  • CombineImports
    Merges consecutive import statements where possible. from module import * is not handled.

  • OptimizeImports (REQUIRES_IMPORT_RESOLVE)
    Remove imports that are not used or are no longer used by transform.
    Module import optimization can be set to three modes via --optimize-module-imports:

    • always: if there's no __all__ or external reference (always optimize)
    • removed: if no longer used by transforms
    • False: always preserve
  • ConvertPass
    Drop pass statements or convert to smallest expression (0).

  • ConvertPosArgs (INFLUENCES_MANGLING)
    Remove positional-only parameter notation (PEP 570 /).
    Performed last since name mangling uses information about positional-only parameter.

  • RemoveDunderAll (INFLUENCES_MANGLING)
    Drops the top-level __all__ assignment.

Experimental transforms

  • ConvertTypeImports
    • Rewrites from typing_extensions import ... to from typing import ... for a fixed set of symbols long-stable in typing, only when the name is on that list.
    • Rewrites from typing import <collections.abc re-exports> to from collections.abc import ..., same as above.
  • InlineFunctions
    Completely remove the function marked with the @terser_hints.inline decorator, and inserts the body at the referenced location.
  • InlineIntFlags
    Remove the enum.IntFlag declaration and replace it with a constant operation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions