diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 42564aa..a18000b 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -1,17 +1,17 @@ # This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: Python package +name: htmd -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] +on: [ push, pull_request ] jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: chartboost/ruff-action@v1 build: - runs-on: ubuntu-latest strategy: fail-fast: false @@ -27,14 +27,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest + python -m pip install pytest python -m pip install . - - 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 diff --git a/htmd/cli.py b/htmd/cli.py index c8f3d9f..e629c16 100644 --- a/htmd/cli.py +++ b/htmd/cli.py @@ -66,16 +66,15 @@ def verify(): msg = f'Post "{post.path}" does not have field {field}.' click.echo(click.style(msg, fg='red')) if 'published' in post.meta: - try: - post.meta.get('published').year - except AttributeError: + published = post.meta.get('published') + if not hasattr(published, 'year'): correct = False - published = post.meta.get('published') msg = ( f'Published date {published} for {post.path}' ' is not in the format YYYY-MM-DD.' ) click.echo(click.style(msg, fg='red')) + if correct: msg = 'All posts are correctly formatted.' click.echo(click.style(msg, fg='green')) @@ -104,9 +103,11 @@ def set_post_time(app, post, field, date_time): with open(file_path, 'w') as file: for line in lines: if not found and field in line: - line = f'{field}: {date_time.isoformat()}\n' + # Update datetime value + line = f'{field}: {date_time.isoformat()}\n' # noqa: PLW2901 found = True elif not found and '...' in line: + # Write field and value before '...' file.write(f'{field}: {date_time.isoformat()}\n') found = True file.write(line) @@ -126,12 +127,12 @@ def set_posts_datetime(app, posts): field = 'updated' post_datetime = post.meta.get(field) - now = datetime.datetime.now() + now = datetime.datetime.now(tz=datetime.UTC) current_time = now.time() if isinstance(post_datetime, datetime.date): post_datetime = datetime.datetime.combine( post_datetime, current_time, - ) + ).replace(tzinfo=datetime.UTC) else: post_datetime = now post.meta[field] = post_datetime @@ -204,7 +205,7 @@ def build(ctx, css_minify, js_minify): default=True, help='If JavaScript should be minified', ) -def preview(ctx, host, port, css_minify, js_minify): +def preview(_ctx, host, port, css_minify, js_minify): from . import site # reload for tests to refresh app.static_folder # otherwise app.static_folder will be from another test diff --git a/htmd/site.py b/htmd/site.py index d5211f5..65c642e 100644 --- a/htmd/site.py +++ b/htmd/site.py @@ -47,9 +47,9 @@ def get_project_dir(): try: with open(os.path.join(project_dir, 'config.toml'), 'rb') as config_file: htmd_config = tomllib.load(config_file) -except IOError: - print('Can not find config.toml') - sys.exit(1) +except FileNotFoundError: + msg = 'Can not find config.toml' + sys.exit(msg) # Flask configs are flat, config.toml is not # Define the configuration keys and their default values @@ -215,7 +215,7 @@ def all_posts(): # If month and day are ints then Flask removes leading zeros @app.route('/////') def post(year, month, day, path): - if len(year) != 4 or len(month) != 2 or len(day) != 2: + if len(year) != 4 or len(month) != 2 or len(day) != 2: # noqa: PLR2004 abort(404) post = posts.get_or_404(path) date_str = f'{year}-{month}-{day}' @@ -225,10 +225,7 @@ def post(year, month, day, path): def tag_in_list(list_of_tags, tag): - for i in list_of_tags: - if i['tag'] == tag: - return True - return False + return any(i['tag'] == tag for i in list_of_tags) def increment_tag_count(list_of_tags, tag): @@ -285,7 +282,7 @@ def not_found(): @app.route('//') def year_view(year): year = str(year) - if len(year) != 4: + if len(year) != len('YYYY'): abort(404) year_posts = [ p for p in posts if year == p.meta.get('published', []).strftime('%Y') @@ -342,13 +339,13 @@ def day_view(year, month, day): @app.errorhandler(404) -def page_not_found(e): +def page_not_found(_e): return render_template('404.html'), 404 # Telling Frozen-Flask about routes that are not linked to in templates @freezer.register_generator -def year_view(): +def year_view(): # noqa: F811 for post in posts: yield { 'year': post.meta.get('published').year, @@ -356,7 +353,7 @@ def year_view(): @freezer.register_generator -def month_view(): +def month_view(): # noqa: F811 for post in posts: yield { 'month': post.meta.get('published').strftime('%m'), @@ -365,7 +362,7 @@ def month_view(): @freezer.register_generator -def day_view(): +def day_view(): # noqa: F811 for post in posts: yield { 'day': post.meta.get('published').strftime('%d'), diff --git a/htmd/utils.py b/htmd/utils.py index a2b5887..2e3cb69 100644 --- a/htmd/utils.py +++ b/htmd/utils.py @@ -19,12 +19,10 @@ def create_directory(name): def combine_and_minify_css(static_folder): # Combine and minify all .css files in the static folder - css_files = sorted( - [ - f for f in os.listdir(static_folder) - if f.endswith('.css') and f != 'combined.min.css' - ] - ) + css_files = sorted([ + f for f in os.listdir(static_folder) + if f.endswith('.css') and f != 'combined.min.css' + ]) if not css_files: # There are no .css files in the static folder return @@ -43,13 +41,11 @@ def combine_and_minify_css(static_folder): def combine_and_minify_js(static_folder): # Combine and minify all .js files in the static folder - js_files = sorted( - [ - f for f in os.listdir(static_folder) - if f.endswith('.js') - and f != 'combined.min.js' - ] - ) + js_files = sorted([ + f for f in os.listdir(static_folder) + if f.endswith('.js') + and f != 'combined.min.js' + ]) if not js_files: # There are no .js files in the static folder return diff --git a/pyproject.toml b/pyproject.toml index 00fd3b0..44c5ba4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ ignore = [ "RET504", "S101", "UP015", + "ANN", "PTH", "I", ] [tool.ruff.lint.flake8-quotes] diff --git a/tests/test_build.py b/tests/test_build.py index 72be7e4..069d535 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -151,7 +151,7 @@ def test_build_page_404(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -178,7 +178,7 @@ def test_build_post_404_invalid_date_year(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -217,7 +217,7 @@ def test_build_post_404_invalid_date_month(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -256,7 +256,7 @@ def test_build_post_404_invalid_date_day(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -284,7 +284,7 @@ def test_build_post_404_different_date(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -325,7 +325,7 @@ def test_build_year_404_incorrect(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -353,7 +353,7 @@ def test_build_year_404_no_posts(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -381,7 +381,7 @@ def test_build_month_404_no_posts(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -409,7 +409,7 @@ def test_build_day_404_no_posts(): with open(os.path.join('pages', 'about.html'), 'r') as about_file: lines = about_file.readlines() - new_line = '''

DNE link

\n''' + new_line = '''

DNE link

\n''' # noqa: E501 with open(os.path.join('pages', 'about.html'), 'w') as about_file: for line in lines: if '

This is the about page.

' in line: @@ -452,10 +452,9 @@ def test_build_updated_time_is_added(): runner.invoke(start) with open(os.path.join('posts', 'example.md'), 'r') as post_file: b_lines = post_file.readlines() - runner.invoke(build) with open(os.path.join('posts', 'example.md'), 'r') as post_file: a_lines = post_file.readlines() - for b_line, a_line in zip(b_lines, a_lines): + for b_line, a_line in zip(b_lines, a_lines, strict=True): if 'updated' in b_line: b_updated = b_line a_updated = a_line @@ -479,7 +478,7 @@ def test_build_updated_time_is_added(): assert b_datetime.minute == 0 assert b_datetime.second == 0 - date_with_current_time = datetime.datetime.now().replace( + date_with_current_time = datetime.datetime.now(tz=datetime.UTC).replace( year=a_datetime.year, month=a_datetime.month, day=a_datetime.day, @@ -505,7 +504,7 @@ def test_build_published_time_is_added(): runner.invoke(build) with open(os.path.join('posts', 'example.md'), 'r') as post_file: a_lines = post_file.readlines() - for b_line, a_line in zip(b_lines, a_lines): + for b_line, a_line in zip(b_lines, a_lines, strict=True): if 'published' in b_line: b_published = b_line a_published = a_line @@ -522,7 +521,7 @@ def test_build_published_time_is_added(): assert b_datetime.minute == 0 assert b_datetime.second == 0 - date_with_current_time = datetime.datetime.now().replace( + date_with_current_time = datetime.datetime.now(datetime.UTC).replace( year=a_datetime.year, month=a_datetime.month, day=a_datetime.day, @@ -559,7 +558,7 @@ def test_build_updated_is_added(): a_datetime_str = a_updated.replace('updated:', '').strip() a_datetime = datetime.datetime.fromisoformat(a_datetime_str) - date_with_current_time = datetime.datetime.now().replace( + date_with_current_time = datetime.datetime.now(datetime.UTC).replace( year=a_datetime.year, month=a_datetime.month, day=a_datetime.day, diff --git a/tests/test_preview.py b/tests/test_preview.py index 0f7e039..185e740 100644 --- a/tests/test_preview.py +++ b/tests/test_preview.py @@ -7,4 +7,6 @@ def test_preview(): with runner.isolated_filesystem(): result = runner.invoke(start) result = runner.invoke(preview) - assert result.exit_code == 5 + # Why is this 5? + expected_exit_code = 5 + assert result.exit_code == expected_exit_code diff --git a/tests/test_verify.py b/tests/test_verify.py index d4eb248..a516e33 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -156,7 +156,7 @@ def test_verify_site_name_empty(): assert result.output == expected_output -def test_verify_SITE_NAME_missing(): +def test_verify_site_name_missing(): expected_output = ( 'All posts are correctly formatted.\n' '[site] name is not set in config.toml.\n'