Pricing of vanillas is basically interpolation of existing (or past) quotes.
It is easier to interpolate in implied volatility space , than in price space.
Reasons are we need to interpolate in multidimensional space (maturity, strike,forward, etc) and satisfy non-arbitrage conditions.
Using Black-scholes formula is convenient mapping which would also ...
If you want to compare quotes across markets or over time it can be useful to use fixed points: eg the 110%/90% points to compute skew or the +/-25 delta points for risk-reversal. You can't rely on quotes existing at exactly those points so you would want to interpolate.
The problem is that you are not pricing the same thing, and for two reasons:
The vanilla instruments you are pricing should start on spot date and have a maturity with that start as reference
The frequency of the fixed leg on the OIS swap should be annual.
If you change you code to:
print('TENOR \t PV \t fairrate% \t fairrate% + fairspread%')
calendar = ql....