text: # -*- coding: utf-8 -*-
  """session_8_decorators.ipynb
  
  Automatically generated by Colaboratory.
  
  Original file is located at
      https://colab.research.google.com/drive/1Jn-YOMoWq67jWa_cP6aHgAsgC8fRzH2C
  """
  
  import time
  from functools import wraps
  from datetime import datetime
  from time import perf_counter
  
  
  def odd_it(fn: "Function"):
  	"""
  	Decorator that allows to run a function only at odd seconds, else prints out "We're even!"
  	"""
  	@wraps(fn)
  	def inner(*args, **kwargs):
  		curr_time = datetime.now()
  		print(curr_time)
  		if curr_time.second % 2 != 0:
  			return fn(*args,**kwargs)
  		else:
  			print("We're even!")
  	return inner
  
  
  def logger(fn: "Function"):
    """
  	Decorator to print the logs
    """
  
    @wraps(fn)
    def inner(*args,**kwargs):
      start_dt = datetime.now()
      result = fn(*args,**kwargs)
      end_dt = datetime.now()
      print(f'{start_dt}: called{fn.__name__}')
      print(f'Total time executed:{end_dt - start_dt}')
      print(f'Function description:\n{fn.__doc__}')
      print(f'Check if function has returned something: {True if result else False}')
      return result
    return inner
  
  
  def authenticate(curr_pwd: str,usr_pwd: str):
  	"""
  	Decorator for authenticate function
  
  	"""
  	def check_pwd(fn:"Function"):
  		@wraps(fn)
  		def inner(*args,**kwargs):
  			if usr_pwd == curr_pwd():
  				print("Authentication successful")
  				return fn(*args,**kwargs)
  			else:
  				print("Password does not match")
  		return inner
  	return check_pwd
  
  
  
  def timed(rep: int):
    """
    Decorator factory runs for the specified number of times as input integer and calculates average time taken for the function to run
    """
    if type(rep) is not int:
      raise TypeError("Invalid type, expected int!")
    if rep < 1:
      raise ValueError("Should conatin atleast 1 iteration")
  
    def time_calc(fn):
      @wraps(fn)
      def inner(*args, **kwargs):
        time_taken = 0
        for _ in range(reps):
          start_time = perf_counter()
          result = fn(*args, **kwargs)
          end_time = perf_counter()
          time_taken += (end_time - start_time)
        avg_run_time = time_taken / rep
        print(f'Avg Run time: {avg_run_time}s ({rep} rep)')
        return result
      return inner
    return time_calc