{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "02e68cf1",
   "metadata": {},
   "source": [
    "# More Decorator Examples\n",
    "\n",
    "Some additional examples beyond what is in 08.decorators."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b985a33b",
   "metadata": {},
   "source": [
    "## Modifying Arguments within newfunc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "31c291f2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def reverse_args(func):\n",
    "    def newfunc(*args):\n",
    "        # within newfunc we are able to write whatever we'd like\n",
    "        # we could decide that we want to reverse the arguments\n",
    "        reversed_args = reversed(args)\n",
    "        return func(*reversed_args)\n",
    "    return newfunc\n",
    "\n",
    "\n",
    "@reverse_args\n",
    "def print_args(*args):\n",
    "    for arg in args:\n",
    "        print(arg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "413cfac8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "print_args(1, 2, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "95e01cf9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.2"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@reverse_args\n",
    "def divide(a, b):\n",
    "    return a / b\n",
    "\n",
    "divide(10, 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d055880d",
   "metadata": {},
   "source": [
    "## Example: Authorization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1590c5de",
   "metadata": {},
   "outputs": [],
   "source": [
    "# perhaps we want a function that checks if a user can perform an action\n",
    "def auth_required(func):\n",
    "    \n",
    "    # list of allowed users. in practice, we'd look this up in a database\n",
    "    allowed_users = (\"lauren\", \"mitch\")\n",
    "    \n",
    "    def newfunc(*args, **kwargs):\n",
    "        # here, we're actually using an argument within newfunc\n",
    "        # by checking if it is in the kwargs dictionary\n",
    "        if kwargs.get(\"auth_user\") in allowed_users:\n",
    "            func(*args, **kwargs)\n",
    "        else:\n",
    "            print(\"ACCESS DENIED\")\n",
    "    return newfunc\n",
    "\n",
    "# these functions must also accept auth_user so that the above call to func(*args, **kwargs)\n",
    "# doesn't send an invalid parameter through\n",
    "@auth_required\n",
    "def withdraw_funds(account, amount, auth_user):\n",
    "    print(f\"withdrew {amount} funds from account={account}\")\n",
    "\n",
    "@auth_required\n",
    "def delete_account(account, auth_user):\n",
    "    print(\"deleted\", account)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f9e8bcd0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "withdrew 100 funds from account=jim\n"
     ]
    }
   ],
   "source": [
    "withdraw_funds(\"jim\", 100, auth_user=\"lauren\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "77a82ae4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ACCESS DENIED\n"
     ]
    }
   ],
   "source": [
    "delete_account(\"kevin\", auth_user=\"jim\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf9a611a",
   "metadata": {},
   "source": [
    "## Modifying Keyword Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "90161162",
   "metadata": {},
   "outputs": [],
   "source": [
    "# if we didn't want auth_user to be passed through, we'd make a small modification to newfunc\n",
    "\n",
    "def auth_required(func):    \n",
    "    allowed_users = (\"lauren\", \"mitch\")\n",
    "    \n",
    "    def newfunc(*args, auth_user, **kwargs):\n",
    "        # newfunc now requires auth_user, and passes through all *other* parameters\n",
    "        if auth_user in allowed_users:\n",
    "            func(*args, **kwargs)\n",
    "        else:\n",
    "            print(\"ACCESS DENIED\")\n",
    "    return newfunc\n",
    "\n",
    "# auth_user is no longer seen in the definition of these functions \n",
    "# but it can be passed in since the newfunc returned from auth_required accepts it\n",
    "@auth_required\n",
    "def withdraw_funds(account, amount):\n",
    "    print(f\"withdrew {amount} funds from account={account}\")\n",
    "\n",
    "@auth_required\n",
    "def delete_account(account):\n",
    "    print(\"deleted\", account)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ee4cabe7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "withdrew 100 funds from account=jim\n"
     ]
    }
   ],
   "source": [
    "withdraw_funds(\"jim\", 100, auth_user=\"lauren\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a22a86d9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ACCESS DENIED\n"
     ]
    }
   ],
   "source": [
    "delete_account(\"kevin\", auth_user=\"jim\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dca4b1ec",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.15"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
