Skip to content

Commit

Permalink
Merge pull request #7 from thiagojacinto/dev
Browse files Browse the repository at this point in the history
feat: version 0.1.1 🎉 - more tests and CI/CD config
  • Loading branch information
thiagojacinto authored Mar 6, 2023
2 parents f8fd149 + 9fd197c commit 43e8783
Show file tree
Hide file tree
Showing 14 changed files with 445 additions and 1 deletion.
40 changes: 40 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: Python application

on:
push:
branches: [ "main", "dev" ]
pull_request:
branches: [ "main", "dev" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10.9
uses: actions/setup-python@v3
with:
python-version: "3.10.9"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
40 changes: 40 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Upload Python Package

on:
release:
types: [published]
branches: [ "main" ]

permissions:
contents: read

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
# time-until-cli
Application that calculate time duration until reach a given date.
> Application that calculate time duration until reach a given date.
**Main objective**: Understanding the logic of _Python_ app publishing and documenting it on a simple project.

## Usage

```bash
time_until 22h
```

## Application flow & use cases

Using CLI to calculate time duration to a given input date or timestamp.

| Input | Output / Response |
| :---- | :---------------- |
| `time-until 23h` | Time remaining: 8 hour(s) 22 minute(s) 42 second(s) |
| `time-until 2023-02-27` | Time remaining: 04 month(s) 14 day(s) 8 hour(s) 22 minute(s) 42 second(s) |

![app-flow-example](assets/time_until_app.png)

## Main goals

Build a Python app that works as a CLI (Command-line Interface) that receives a future date or time and returns a calculation of remaining time from now until that given date or time.

Once working, this project must be configured and submitted as Python package thru PyPI Modules. The process of development, build, release and publishing is the core of the project, to understand it and provice ideas and thoghts of process automation.

Feel free to initiate a discusison, open a issue or a pull request to this project. All kinds of contributions and ideas are welcome. **_Let's code!_**
1 change: 1 addition & 0 deletions assets/time_until_app.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mxfile host="app.diagrams.net" modified="2023-02-26T13:07:53.290Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" etag="bepQZm-S_8wZlN24tvgk" version="14.6.3" type="device"><diagram id="iOcOu5OnF31ByhzuMogO" name="Página-1">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</diagram></mxfile>
Binary file added assets/time_until_app.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "time_until"
authors = [
{ name="Thiago Jacinto", email="[email protected]" },
]
description = "Application that calculate time duration until reach a given date"
readme = "README.md"
requires-python = ">=3.10.9"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
"Development Status :: 4 - Beta"
]
dynamic = [
"version",
"dependencies"
]

[project.scripts]
time_until = "time_until:app"

[project.urls]
"Homepage" = "https://github.com/thiagojacinto/time-until-cli"
"Bug Tracker" = "https://github.com/thiagojacinto/time-until-cli/issues"
"General Discussions" = "https://github.com/thiagojacinto/time-until-cli/discussions"

[tool.setuptools.dynamic]
version = {attr = "time_until.__version__"}
dependencies = {file = ["requirements.txt"]}
16 changes: 16 additions & 0 deletions requirements-development.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
attrs==22.2.0
click==8.1.3
colorama==0.4.6
commonmark==0.9.1
exceptiongroup==1.1.0
iniconfig==2.0.0
packaging==23.0
pluggy==1.0.0
Pygments==2.14.0
pytest==7.2.1
python-dateutil==2.8.2
rich==12.6.0
shellingham==1.5.0.post1
six==1.16.0
tomli==2.0.1
typer==0.7.0
15 changes: 15 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
attrs==22.2.0
click==8.1.3
colorama==0.4.6
commonmark==0.9.1
exceptiongroup==1.1.0
iniconfig==2.0.0
packaging==23.0
pluggy==1.0.0
Pygments==2.14.0
python-dateutil==2.8.2
rich==12.6.0
shellingham==1.5.0.post1
six==1.16.0
tomli==2.0.1
typer==0.7.0
Empty file added src/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions src/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from time_until import app
app()
68 changes: 68 additions & 0 deletions src/time_until.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Application that calculate time duration until reach a given date."""
from datetime import datetime
from typing import Optional
import typer
from dateutil.relativedelta import relativedelta
from dateutil.parser import parse

__version__ = "0.1.1"

app = typer.Typer(
pretty_exceptions_show_locals=False,
help="Application that calculate time duration until reach a given date."
)

def version_callback(value: bool):
if value:
print(f"time_until CLI Version: {__version__}")
raise typer.Exit()

def validate_date(target: str):
"""Validate with the reference date format"""
parsed_target = parse(target)
return (True, parsed_target)

def calculate_delta(origin: datetime, target: datetime):
"""calculate time duration from ORIGIN to TARGET"""
return relativedelta(origin, target)

def print_output(delta: relativedelta):
"""Define a way to output information from the `relativedelta` input"""
result=[]
if delta.years > 0:
result.append("{} year(s) ".format(delta.years))
if delta.months > 0:
result.append("{} month(s) ".format(delta.months))
if delta.days > 0:
result.append("{} day(s) ".format(delta.days))
if delta.hours > 0:
result.append("{} hour(s) ".format(delta.hours))
if delta.minutes > 0:
result.append("{} minute(s) ".format(delta.minutes))
if delta.seconds > 0:
result.append("{} second(s) ".format(delta.seconds))

result.insert(0, 'Time remaining: ')
print(''.join(result))

@app.command()
def time_until(
target: str = typer.Argument(..., help="Future date or time used as reference."),
version: Optional[bool] = typer.Option(
None, "--version", callback=version_callback, is_eager=True
)
):
"""Application that calculate time duration until reach a given date."""

is_valid, parsed_target = validate_date(target)
rightnow = datetime.now()

if parsed_target < datetime.now():
raise ValueError("Not possible to calculate duration to a past date or time. Try again with future date OR time.")

if is_valid:
result = calculate_delta(parsed_target, rightnow)
print_output(result)

if __name__ == "__main__":
app()
Empty file added tests/__init__.py
Empty file.
48 changes: 48 additions & 0 deletions tests/date_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from datetime import datetime
from dateutil.relativedelta import relativedelta

class DateBuilder:
"""Builder to generate a Date entity"""

def __init__(self):
"""Initialise with datetime object of current time"""
self._date = datetime.now()

def with_years_ahead(self, years_from_now : int):
"""Set the the number of years from now"""
self._date += relativedelta(years=years_from_now)
return self

def with_months_ahead(self, months_from_now : int):
"""Set the the number of months from now"""
self._date += relativedelta(months=months_from_now)
return self

def with_days_ahead(self, days_from_now : int):
"""Set the the number of days from now"""
self._date += relativedelta(days=days_from_now)
return self

def with_hours_ahead(self, hours_from_now : int):
"""Set the the number of hours from now"""
self._date += relativedelta(hours=hours_from_now)
return self

def with_minutes_ahead(self, minutes_from_now : int):
"""Set the the number of minutes from now"""
self._date += relativedelta(minutes=minutes_from_now)
return self

def with_seconds_ahead(self, seconds_from_now : int):
"""Set the the number of seconds from now"""
self._date += relativedelta(seconds=seconds_from_now)
return self

def with_seconds_ago(self, seconds_ago : int):
"""Set the the number of seconds ago from the current time"""
self._date -= relativedelta(seconds=seconds_ago)
return self

def build(self):
"""Return the curret datetime entity"""
return self._date
Loading

0 comments on commit 43e8783

Please sign in to comment.