Skip to content

Commit

Permalink
short url generator
Browse files Browse the repository at this point in the history
  • Loading branch information
hitnik committed Aug 19, 2021
1 parent 9fc6fd7 commit 268c10c
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 23 deletions.
1 change: 0 additions & 1 deletion app/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

DB_PATH = os.path.join(BASEDIR, 'db.sqlite3')


def init_db(db_path):
"""init sqlite database, create sqlite file if needed
Expand Down
77 changes: 64 additions & 13 deletions app/utils.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import argparse
import textwrap
from db import ( short_url_exist, get_short_url,
get_long_url_from_db, long_url_exist,
get_short_url_by_long
from db import (insert_long_url, short_url_exist, get_short_url,
get_long_url_from_db, long_url_exist,
get_short_url_by_long, insert_short_url,
insert_long_url
)
import shortuuid
from urllib.parse import urlunsplit
from config import NETLOC, SCHEME


class URLExistsError(Exception):
def __init__(self, *args):
super().__init__(*args)
self.message = "This short URL already exists"


class URLNotFoundError(Exception):
def __init__(self, *args: object):
super().__init__(*args)
self.message = "This short URL does not exist"


def parser():
parser = argparse.ArgumentParser(
description="URL shortener app.",
formatter_class=argparse.RawTextHelpFormatter
)
description="URL shortener app.",
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('url', metavar='URL', type=str,
help=textwrap.dedent("""
help=textwrap.dedent("""
Provide URL here.\r
If you want to shorten URL, """ +
"""provide it with [--generate] argument.\r
"""provide it with [--generate] argument.\r
If you want to get long URL, """ +
"""provide short URL without any other arguments.
"""provide short URL without any other arguments.
"""),
)
parser.add_argument('--generate', action='store_true', default=False,
Expand All @@ -27,25 +43,60 @@ def parser():
help="""Use this argument and cpecify short URL, if you want to use custom short_url."""
)

return parser
return parser


class Shortener:


@staticmethod
def get_long_url(short):
""" get long url by short url
Args:
short (str): short url
Raises:
Exception: Raises Exception when short url does not exists
Returns:
[str]: short url
"""
if short_url_exist(short):
short_inst = get_short_url(short)
long_inst = get_long_url_from_db(id=short_inst[1])
return long_inst[1]
else:
raise Exception("This short URL does not exist")

raise URLNotFoundError

@staticmethod
def gen_short_url(long):
""" Generates short url from long url.
If long url exists in DB return existing short url,
otherwise generate new short url
Args:
long (str): long url
Returns:
str: short url
"""
if long_url_exist(long):
long_inst = get_long_url_from_db(url=long)
short_inst = get_short_url_by_long(long_inst[0])
return short_inst[2]
else:
uuid = shortuuid.uuid(name=long)[:7]
short_url = urlunsplit((SCHEME, NETLOC, uuid, '', ''))
long_id = insert_long_url(long)
insert_short_url(short_url, long_id)
return short_url

@staticmethod
def save_url(short, long):
if not short_url_exist(short):
if long_url_exist(long):
long_inst = get_long_url_from_db(url=long)
insert_short_url(short, long_inst[0])
return short
else:
raise URLExistsError
23 changes: 18 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import os
import sys
from app.utils import (
parser, Shortener,
URLExistsError, URLNotFoundError
)
from app.db import DB_PATH, init_db



from app.utils import parser
def main():
if not os.path.exists(DB_PATH):
init_db(DB_PATH)
args = parser().parse_args()
print(args)
if not args.generate:
try:
Shortener.get_long_url(args.url)
except URLNotFoundError:
print("URL does not exists", file=sys.stderr)


if __name__ == '__main__':
parser = parser()
args = parser.parse_args()
print(args)
main()
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

@pytest.fixture
def db_path():
db_path = os.path.join(tempfile.mkdtemp(), 'db.sqlite3')
db_path = os.path.join(tempfile.mkdtemp(), 'db1.sqlite3')
return db_path


Expand Down
2 changes: 1 addition & 1 deletion tests/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ def test_parser(argparser):
assert args.url is 'test_url'
assert args.generate is True
assert args.short_url is 'short'


29 changes: 29 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from main import main
from pytest_mock import mocker
import pytest
from argparse import Namespace
from test_db import script
from unittest import mock
from app.db import get_db, close_db, init_db
from argparse import ArgumentParser
import re



def test_main_noparams(db_path, mocker):
mocker.patch('main.DB_PATH', db_path)
with pytest.raises(SystemExit):
main()

def test_main_short_url(db_path, argparser, mocker, capsys):
mocker.patch('main.DB_PATH', db_path)
init_db(db_path=db_path)
with mock.patch('app.db.DB_PATH', db_path):
db = get_db()
db.executescript(script)
args = argparser.parse_args(['on.ln'])
parser = mocker.patch('argparse.ArgumentParser.parse_args', return_value=args)
main()
captured = capsys.readouterr()
print(captured)
assert 'URL does not exists\n' == captured.err
16 changes: 14 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from app.utils import Shortener
from os import name
from urllib.parse import urlencode
from app.utils import Shortener, URLNotFoundError, URLExistsError
from tests.test_db import script, manager_mock
import pytest
from unittest import mock
Expand All @@ -7,7 +9,7 @@
def test_get_long_url(db_mock):
db_mock.executescript(script)
with manager_mock(db_mock, 'db.get_db', 'db.db_manager'):
with pytest.raises(Exception, match=r".* URL does .*"):
with pytest.raises(URLNotFoundError, match=r".* URL does not .*"):
Shortener.get_long_url('raise')
inst = Shortener.get_long_url('goo.gl')
assert type(inst) is str
Expand All @@ -19,3 +21,13 @@ def test_get_long_url(db_mock):
inst = Shortener.gen_short_url('https://www.google.com/')
assert type(inst) is str
assert inst == 'goo.gl'
inst = Shortener.gen_short_url('http://www.onliner.by')
assert type(inst) is str

def test_save_url(db_mock):
db_mock.executescript(script)
with manager_mock(db_mock, 'db.get_db', 'db.db_manager'):
with pytest.raises(URLExistsError):
Shortener.save_url('goo.gl', 'https://www.google.com/')
short = Shortener.save_url('on.by/ptrer', 'http://www.onliner.by')
assert isinstance(short, str)

0 comments on commit 268c10c

Please sign in to comment.