Skip to content

Commit

Permalink
First Release (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
shinichi-takayanagi authored May 13, 2021
1 parent 9c42aba commit 8a26a65
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 1 deletion.
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI
on: pull_request

jobs:
ci:
strategy:
fail-fast: false
matrix:
python-version: [3.9]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
run: |
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
- name: Add path for Poetry
run: echo "$HOME/.poetry/bin" >> $GITHUB_PATH
- name: Install Dependencies
run: poetry install --no-interaction
- name: Run tests
run: poetry run pytest
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
# netcleanser
# netcleanser

The library makes parsing and manipulation of URL🌐 and Email address📧 easy.

![ci](https://github.com/y-bar/netcleanser/workflows/ci/badge.svg?branch=master)
[![license](https://img.shields.io/github/license/y-bar/netcleanser.svg)](https://github.com/y-bar/netcleanser/blob/master/LICENSE)
[![release](https://img.shields.io/github/release/y-bar/netcleanser.svg)](https://github.com/y-bar/netcleanser/releases/latest)


## Install

```bash
pip install netcleanser
```

## How to use

### Email

```python
>>> from netcleanser import Email
>>> email = Email('[email protected]')
>>> email.domain
'gmail.com'
>>> email.local_part
'shinichi.takayanagi'
>>> email.is_valid()
True
>>> email.value
'[email protected]'
```

This `Email` class is `settable` and `dictable`
```python
# As dict
>>> x = {email: 1}
>>> x[email]
1
# As set
>>> {Email.build(), email, email, email}
{Email(value='[email protected])', Email(value='[email protected])'}
```
1 change: 1 addition & 0 deletions netcleanser/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from netcleanser.email import Email
68 changes: 68 additions & 0 deletions netcleanser/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import re
from typing import Optional, Final

# Thanks!
# https://gist.github.com/neu5ron/66078f804f16f9bda828
DOMAIN_NAME_REGEX: Final[str] = re.compile(r'(([\da-zA-Z])([_\w-]{,62})\.){,127}(([\da-zA-Z])[_\w-]{,61})?([\da-zA-Z]\.((xn\-\-[a-zA-Z\d]+)|([a-zA-Z\d]{2,})))', re.IGNORECASE)

def _looks_domain(x: str) -> bool:
domain_name = x.lower().strip().encode('ascii')
return True if re.match(DOMAIN_NAME_REGEX, x) else False

def _automatic_correction(email: str) -> str:
return email.replace("@", "@")

class Email:
def __init__(self, value: Optional[str] = None):
self._set_to_none()
if value is None:
return
try:
self._value = _automatic_correction(value)
self._local_part, self._domain = self._value.split('@')
except:
if _looks_domain(value):
self._local_part = ""
self._domain = value
self._value = f"@{self._domain}"
else:
self._set_to_none()

def _set_to_none(self):
self._value = None
self._local_part = None
self._domain = None

def __str__(self):
return self._value

def __repr__(self):
# The same format with dataclass ;)
return f"Email(value='{self._value})'"

def __eq__(self, other):
if not isinstance(other, Email):
return False
return self._value == other._value

def __hash__(self):
return hash(self._value)

def is_valid(self) -> bool:
return (self._value is not None)

@property
def domain(self) -> str:
return self._domain

@property
def value(self) -> str:
return self._value

@property
def local_part(self) -> str:
return self._local_part

@staticmethod
def build(local_part: str = "dummy", domain: str = "dummy.com"):
return Email(f"{local_part}@{domain}")
16 changes: 16 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[tool.poetry]
name = "netcleanser"
version = "0.1.0"
description = "The library makes parsing and manipulation of URL🌐 and Email address📧 easy."
authors = ["Shinichi Takayanagi <[email protected]>", "Nakamura Michihiro <[email protected]>"]
license = "MIT"

[tool.poetry.dependencies]
python = "^3.9"

[tool.poetry.dev-dependencies]
pytest = "^6.2.4"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Empty file added tests/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions tests/test_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from netcleanser import Email


def test_email():
for value in ["[email protected]", "hoge.moge@gmail.com"]:
email = Email(value)
assert email.is_valid() == True
assert email.local_part == "hoge.moge"
assert email.domain == "gmail.com"
assert str(email) == email.value
assert Email.build(email.local_part, email.domain) == email

def test_empty_local_part():
for value in ["gmail.com", "@gmail.com"]:
email = Email(value)
assert email.is_valid() == True
assert email.local_part == ""
assert email.domain == "gmail.com"
assert str(email) == email.value
assert Email.build(email.local_part, email.domain) == email

def test_internationalized_domain():
for value in ["あうふへぇ@ほげほげ.com", "あうふへぇ@ほげほげ.com"]:
email = Email(value)
assert email.is_valid() == True
assert email.local_part == "あうふへぇ"
assert email.domain == "ほげほげ.com"
assert str(email) == email.value
assert Email.build(email.local_part, email.domain) == email

def test_email_is_invalid():
for value in ["", "akdsjfkjh", None]:
email = Email(value)
assert email.is_valid() == False
assert email.local_part is None
assert email.domain is None
assert email.value is None

def test_email_build():
email = Email().build(domain="hoge.com")
assert email.local_part == "dummy"
assert email.domain == "hoge.com"

email = Email.build(local_part="hoge")
assert email.local_part == "hoge"
assert email.domain == "dummy.com"

def test_email_should_be_settable():
{Email("[email protected]"), Email("xxx@yahooo")}

def test_email_should_be_dictable():
{Email("[email protected]"): 123, Email("xxx@yahooo"): 456}

0 comments on commit 8a26a65

Please sign in to comment.