bare(func) (plain wrapper, no wraps) and proper(func) (with @wraps(func)), each just delegating. Then names(f) returns f.__name__ after decoration: bare-decorated functions report 'wrapper', proper ones keep their own name — the debugging/tooling reason wraps exists.names(bare(greet)), names(proper(greet))
('wrapper', 'greet')wraps copied the metadata; the bare one lost it.
@wraps(func) sits on the inner wrapper.
__doc__ and __qualname__ are copied too.