Skip to content

Commit dc6c9bb

Browse files
Merge pull request #71 from ModischFabrications/feature/multi-stocks
Multiple stocks for solver
2 parents 90b39ef + 345f0f7 commit dc6c9bb

25 files changed

+1074
-527
lines changed

.github/workflows/ci.yml

+9-3
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,18 @@ jobs:
4343
- name: Lint with flake8 🔍
4444
run: |
4545
# stop the build if there are Python syntax errors or undefined names
46-
pipenv run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
47-
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
48-
pipenv run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
46+
pipenv run flake8 tests/ app/ --count --select=E9,F63,F7,F82 --show-source --statistics
47+
# exit-zero treats all errors as warnings
48+
pipenv run flake8 tests/ app/ --count --exit-zero --max-complexity=10 --max-line-length=120 --statistics
49+
50+
- name: Test with mypy 🔍
51+
run: |
52+
# stop the build if there are typing errors
53+
pipenv run python -m mypy app/ tests/
4954
5055
- name: Test with pytest 🔍
5156
run: |
57+
# stop the build if there are failed tests
5258
pipenv run python -m pytest --durations=10
5359
5460
build-and-push-docker:

.pre-commit-config.yaml

+14-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ default_language_version:
66

77
repos:
88
- repo: https://github.com/pre-commit/pre-commit-hooks
9-
rev: v2.4.0
9+
rev: v4.5.0
1010
hooks:
1111
# https://blog.mphomphego.co.za/blog/2019/10/03/Why-you-need-to-stop-using-Git-Hooks.html
1212
- id: check-ast
@@ -49,8 +49,16 @@ repos:
4949
- id: requirements-txt-fixer
5050
name: requirements-txt-fixer
5151
description: Sorts entries in requirements.txt
52+
- id: check-json
53+
name: check-json
54+
description: Attempts to load all json files to verify syntax.
5255

53-
#bandit, vulture?
56+
- repo: https://github.com/pre-commit/mirrors-mypy
57+
rev: v1.9.0
58+
hooks:
59+
- id: mypy
60+
name: mypy
61+
description: Check typing
5462

5563
- repo: local
5664
hooks:
@@ -63,9 +71,9 @@ repos:
6371
language: system
6472
# git version check only needed if version could have changed
6573
files: main.py
66-
types: [python]
74+
types: [ python ]
6775
# TODO: use post-commit
68-
stages: [push]
76+
stages: [ push ]
6977

7078
- id: tests
7179
name: run tests
@@ -74,5 +82,5 @@ repos:
7482
pass_filenames: false
7583
entry: pipenv run python -m pytest -sv
7684
language: system
77-
types: [python]
78-
stages: [push]
85+
types: [ python ]
86+
stages: [ push ]

Pipfile

+2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ flake8 = "==7.0.0"
1212
httpx = "==0.26.0"
1313
black = "==24.3.0"
1414
pytest-cov = "==5.0.0"
15+
mypy = "==1.9.0"
1516

1617
[packages]
1718
fastapi = "==0.109.1"
1819
uvicorn = "==0.26.0"
1920
pydantic-settings = "==2.2.1"
21+
more-itertools = "10.2.0"
2022

2123
[requires]
2224
python_version = "3.11"

Pipfile.lock

+68-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ This Solver is using integers exclusively, as there is no need for arbitrary pre
1818
Feel free to shift your numbers a few decimals if you need fractions.
1919
It has no concept of units, so you can use whatever you want.
2020

21-
*Nerd talk*: This is the 2D "Cutting Stock Problem", which is NP-hard. It can be reduced to the Bin-Packing-Problem (
22-
BPP).
21+
*Nerd talk*: This is the 2D "Cutting Stock Problem", which is NP-hard.
2322
No algorithm exists to calculate a perfect solution in polynomial time, therefore brute force (perfect
2423
solution) is used for small jobs (usually <12 entries) and FFD (fast solution) für larger ones.
2524
Don't be surprised if you get different results, many combinations have equal trimmings and are therefore seen as
@@ -73,17 +72,23 @@ You might need to replace `#!/bin/sh` with `#!/usr/bin/env sh` in the resulting
7372
All obvious errors should be checked and or fixed by pre-commit, execute `pre-commit run --all-files --hook-stage push`
7473
to run manually.
7574

75+
use `git push --no-verify` if you really need to skip these tests, but you better have a good explanation.
76+
7677
Change version number in main.py:version for newer releases, git tags will be created automatically.
7778

7879
### Testing
7980

8081
Remember to test your changes using `pytest`. This will happen automatically both in pre-commit and in CI/CD, but manual
8182
tests will reduce iteration times.
8283

84+
Make sure your changes keep app.* imports or pytest will crash and burn due to missing import settings.
85+
8386
Code coverage and runtimes can be checked
8487
using `pipenv run python -m pytest --durations=5 --cov=app/ --cov-report term-missing`.
8588
Make sure that all critical parts of the code are covered, at v1.0.1 it is at 94%.
8689

90+
Proper type usage can be checked using `pipenv run python -m mypy app`.
91+
8792
### Development Docker Images
8893

8994
1. Build and start this image using `docker-compose up`
@@ -127,14 +132,17 @@ This project uses:
127132

128133
* [FastAPI](https://github.com/tiangolo/fastapi): easy API (this includes much more!)
129134
* [Uvicorn](https://github.com/encode/uvicorn): async web server
135+
* [more-itertools](https://github.com/more-itertools/more-itertools): higher performance permutations
130136

131137
Also used for development is:
132138

133139
* [pipenv](https://github.com/pypa/pipenv): library management
134140
* [httpie](https://github.com/jakubroztocil/httpie): simpler `curl` for docker healthchecks
135141
* [pytest](https://pytest.org): A lot nicer unit tests
136142
* [flake8](https://flake8.pycqa.org/): Linting
143+
* [mypy](https://mypy-lang.org/): Static type checking
137144
* [requests](https://requests.readthedocs.io/): simple HTTP requests
145+
* [httpx](https://www.python-httpx.org/): requirement of TestClient
138146
* [black](https://github.com/psf/black): uncompromising code formatter; currently unused
139147

140148
## External links

app/main.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
from contextlib import asynccontextmanager
33

44
from fastapi import FastAPI
5-
from starlette.middleware.cors import CORSMiddleware
5+
from fastapi.middleware.cors import CORSMiddleware
66
from starlette.requests import Request
77
from starlette.responses import HTMLResponse, PlainTextResponse
88

99
from app.settings import version, solverSettings
10-
# don't mark /app as a sources root or pycharm will delete the "app." prefix
11-
# that's needed for pytest to work correctly
1210
from app.solver.data.Job import Job
1311
from app.solver.data.Result import Result
1412
from app.solver.solver import solve
@@ -55,10 +53,10 @@ async def catch_exceptions_middleware(request: Request, call_next):
5553
)
5654

5755

58-
# response model ensures correct documentation
59-
@app.post("/solve", response_model=Result)
56+
# response model ensures correct documentation, exclude skips optional
57+
@app.post("/solve", response_model=Result, response_model_exclude_defaults=True)
6058
def post_solve(job: Job):
61-
# pydantic guarantees type safety, no need to check manually
59+
# pydantic guarantees type safety, no need to check inputs
6260
solved: Result = solve(job)
6361

6462
return solved

app/settings.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
from pydantic_settings import BaseSettings
33

44
# constant; used for git tags
5-
version = "v1.0.2"
5+
version = "v1.1.0"
66

77

88
class SolverSettings(BaseSettings):
9-
# Desktop with Ryzen 2700X:
10-
# (4, 3, 2)=1260 => 0.1s, (4, 3, 3)=4200 => 0.8s, (5, 3, 3)=9240 => 8s
11-
bruteforce_max_combinations: PositiveInt = 5000
9+
# print n_combinations from tests to find the limit
10+
bruteforce_max_combinations: PositiveInt = 9000
1211
# that is already unusable x100, but the solver takes it easily
1312
solver_n_max: PositiveInt = 2000
1413

0 commit comments

Comments
 (0)