Skip to content

Commit

Permalink
draft of password generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Zepolimer committed Feb 17, 2024
1 parent af2115b commit 4d02d90
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 1 deletion.
29 changes: 29 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Python Password Generator

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v1
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Test with unittest
run: |
python3 -m unittest discover .
- name: Creating package
run: |
python3 setup.py bdist_wheel
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
140 changes: 140 additions & 0 deletions pwd_generator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import string
import random
from functools import reduce


class Pwd:
LOWER_CASES = string.ascii_lowercase
UPPER_CASES = string.ascii_uppercase
LETTERS = string.ascii_letters
DIGITS = string.digits
SPECIALS = string.punctuation

def __init__(self):
self.value = None
self.choices = []

def _set(self, length=None):
if length is not None and length <= 0:
raise ValueError('Password length cannot be less than or equal to 0')
if len(self.choices) == 0:
raise ValueError('You must select at least one parameter if you wish to generate a password')

self.value = ''.join(
random.choices(
reduce(lambda x, y: x + y, self.choices),
k=length or 10
)
)
return self


class LowerCasesPassword(Pwd):
def __init__(self):
super().__init__()

def generate(self, length=None):
"""
Generate a password containing only lower-case letters
:param int length: optional parameter (10 by default)
"""

self.choices = [self.LOWER_CASES]
return self._set(length=length)


class UpperCasesPassword(Pwd):
def __init__(self):
super().__init__()

def generate(self, length=None):
"""
Generate a password containing only upper-case letters
:param int length: optional parameter (10 by default)
"""

self.choices = [self.UPPER_CASES]
return self._set(length=length)


class LettersPassword(Pwd):
def __init__(self):
super().__init__()

def generate(self, length=None):
"""
Generate a letter-only password
:param int length: optional parameter (10 by default)
"""

self.choices = [self.LETTERS]
return self._set(length=length)


class DigitsPassword(Pwd):
def __init__(self):
super().__init__()

def generate(self, length=None):
"""
Generate a number-only password
:param int length: optional parameter (10 by default)
"""

self.choices = [self.DIGITS]
return self._set(length=length)


class SpecialsPassword(Pwd):
def __init__(self):
super().__init__()

def generate(self, length=None):
"""
Generate a password containing only special characters
:param int length: optional parameter (10 by default)
"""

self.choices = [self.SPECIALS]
return self._set(length=length)


class Password(Pwd):
def __init__(self):
super().__init__()

def generate(
self,
length=None,
lower_cases=True,
upper_cases=True,
digits=True,
specials=True
):
"""
Generate a password containing only special characters
:param int length: optional parameter (10 by default)
:param bool lower_cases: optional parameter (True by default)
:param bool upper_cases: optional parameter (True by default)
:param bool digits: optional parameter (True by default)
:param bool specials: optional parameter (True by default)
"""

choices = [
self.LOWER_CASES,
self.UPPER_CASES,
self.DIGITS,
self.SPECIALS
]

if not lower_cases:
choices.remove(self.LOWER_CASES)
if not upper_cases:
choices.remove(self.UPPER_CASES)
if not digits:
choices.remove(self.DIGITS)
if not specials:
choices.remove(self.SPECIALS)

self.choices = choices
return self._set(length=length)
74 changes: 74 additions & 0 deletions pwd_generator/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import unittest

from pwd_generator import (
LowerCasesPassword,
UpperCasesPassword,
LettersPassword,
DigitsPassword,
SpecialsPassword,
Password
)


class GeneratePasswordTestCase(unittest.TestCase):
def test_generate_lower_cases_password(self):
password = LowerCasesPassword()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(length=20)
self.assertEqual(len(password.value), 20)
self.assertEqual(password.value.islower(), True)

def test_generate_upper_cases_password(self):
password = UpperCasesPassword()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(length=12)
self.assertEqual(len(password.value), 12)
self.assertEqual(password.value.isupper(), True)

def test_generate_letters_password(self):
password = LettersPassword()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(length=15)
self.assertEqual(len(password.value), 15)

def test_generate_digits_password(self):
password = DigitsPassword()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(length=17)
self.assertEqual(len(password.value), 17)
self.assertEqual(password.value.isnumeric(), True)

def test_generate_specials_password(self):
password = SpecialsPassword()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(length=19)
self.assertEqual(len(password.value), 19)

def test_generate_custom_password(self):
password = Password()

password.generate()
self.assertEqual(len(password.value), 10)

password.generate(
length=20,
specials=False,
digits=True,
lower_cases=False
)
self.assertEqual(len(password.value), 20)
26 changes: 26 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from pathlib import Path

import setuptools
from pkg_resources import parse_requirements

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="pwd_generator",
version='0.0.1',
author="Rémi Lopez",
author_email="contact.remilopez@gmail.com",
description="An open-source password generator",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/pwd-generator",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.8',
include_package_data=True,
)

0 comments on commit 4d02d90

Please sign in to comment.