flixopt 2.1.5__tar.gz → 2.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flixopt might be problematic. Click here for more details.
- {flixopt-2.1.5 → flixopt-2.1.7}/.github/CONTRIBUTING.md +2 -2
- flixopt-2.1.7/.github/ISSUE_TEMPLATE/bug_report.yml +111 -0
- flixopt-2.1.7/.github/ISSUE_TEMPLATE/config.yml +14 -0
- flixopt-2.1.7/.github/ISSUE_TEMPLATE/feature_request.yml +127 -0
- flixopt-2.1.7/.github/ISSUE_TEMPLATE/general_issue.yml +40 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/.github/pull_request_template.md +3 -3
- flixopt-2.1.7/.github/workflows/python-app.yaml +354 -0
- flixopt-2.1.7/.pre-commit-config.yaml +16 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/CHANGELOG.md +51 -2
- {flixopt-2.1.5 → flixopt-2.1.7}/PKG-INFO +41 -20
- {flixopt-2.1.5 → flixopt-2.1.7}/README.md +15 -10
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/SUMMARY.md +2 -2
- flixopt-2.1.7/docs/contribute.md +45 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/examples/00-Minimal Example.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/examples/01-Basic Example.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/examples/02-Complex Example.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/examples/index.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/faq/contribute.md +26 -14
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/faq/index.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/javascripts/mathjax.js +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/Bus.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +13 -13
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/Flow.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/LinearConverter.md +2 -2
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/Piecewise.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/Storage.md +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/Mathematical Notation/index.md +1 -1
- flixopt-2.1.7/docs/user-guide/Mathematical Notation/others.md +3 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/user-guide/index.md +2 -2
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/02_Complex/complex_example.py +1 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/02_Complex/complex_example_results.py +0 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/__init__.py +4 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/aggregation.py +0 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/calculation.py +3 -7
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/components.py +140 -21
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/core.py +10 -6
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/effects.py +2 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/elements.py +5 -3
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/features.py +17 -13
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/flow_system.py +54 -0
- flixopt-2.1.7/flixopt/network_app.py +755 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/structure.py +1 -3
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt.egg-info/PKG-INFO +41 -20
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt.egg-info/SOURCES.txt +5 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt.egg-info/requires.txt +22 -5
- {flixopt-2.1.5 → flixopt-2.1.7}/mkdocs.yml +1 -1
- {flixopt-2.1.5 → flixopt-2.1.7}/pyproject.toml +36 -13
- flixopt-2.1.7/renovate.json +16 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/scripts/extract_release_notes.py +5 -5
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/conftest.py +19 -10
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_bus.py +26 -14
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_component.py +55 -35
- flixopt-2.1.7/tests/test_effect.py +168 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_flow.py +101 -76
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_integration.py +1 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_io.py +1 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_linear_converter.py +62 -116
- flixopt-2.1.7/tests/test_network_app.py +29 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_on_hours_computation.py +48 -45
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_results_plots.py +2 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_storage.py +49 -55
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/todos.txt +2 -2
- flixopt-2.1.5/.github/ISSUE_TEMPLATE/bug_report.yml +0 -81
- flixopt-2.1.5/.github/ISSUE_TEMPLATE/config.yml +0 -8
- flixopt-2.1.5/.github/ISSUE_TEMPLATE/feature_request.yml +0 -88
- flixopt-2.1.5/.github/workflows/python-app.yaml +0 -223
- flixopt-2.1.5/docs/contribute.md +0 -49
- flixopt-2.1.5/docs/user-guide/Mathematical Notation/others.md +0 -3
- flixopt-2.1.5/tests/test_effect.py +0 -142
- {flixopt-2.1.5 → flixopt-2.1.7}/.gitignore +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/LICENSE +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/examples/03-Calculation Modes.md +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/getting-started.md +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/images/architecture_flixOpt-pre2.0.0.png +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/images/architecture_flixOpt.png +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/images/flixopt-icon.svg +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/docs/index.md +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/00_Minmal/minimal_example.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/01_Simple/simple_example.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/03_Calculation_types/Zeitreihen2020.csv +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/examples/03_Calculation_types/example_calculation_types.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/commons.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/config.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/config.yaml +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/interface.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/io.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/linear_converters.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/plotting.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/results.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/solvers.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt/utils.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt.egg-info/dependency_links.txt +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/flixopt.egg-info/top_level.txt +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/pics/architecture_flixOpt-pre2.0.0.png +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/pics/architecture_flixOpt.png +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/pics/flixOpt_plotting.jpg +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/pics/flixopt-icon.svg +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/pics/pics.pptx +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/scripts/gen_ref_pages.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/setup.cfg +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/__init__.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/ressources/Zeitreihen2020.csv +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/run_all_tests.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_dataconverter.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_examples.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_functional.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_plots.py +0 -0
- {flixopt-2.1.5 → flixopt-2.1.7}/tests/test_timeseries.py +0 -0
|
@@ -58,7 +58,7 @@ def create_storage(
|
|
|
58
58
|
) -> Storage:
|
|
59
59
|
"""
|
|
60
60
|
Create a battery storage component.
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
Args:
|
|
63
63
|
label: Unique identifier
|
|
64
64
|
capacity_kwh: Storage capacity [kWh]
|
|
@@ -82,4 +82,4 @@ def create_storage(
|
|
|
82
82
|
|
|
83
83
|
---
|
|
84
84
|
|
|
85
|
-
**Every contribution helps advance sustainable energy solutions! 🌱⚡**
|
|
85
|
+
**Every contribution helps advance sustainable energy solutions! 🌱⚡**
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
name: 🐛 Bug Report
|
|
2
|
+
description: Report a bug in flixopt
|
|
3
|
+
title: "[BUG] "
|
|
4
|
+
labels: ["type: bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for taking the time to fill out this bug report!
|
|
10
|
+
|
|
11
|
+
**Before submitting**: Please search [existing issues](https://github.com/flixOpt/flixopt/issues) to avoid duplicates.
|
|
12
|
+
|
|
13
|
+
- type: checkboxes
|
|
14
|
+
id: checks
|
|
15
|
+
attributes:
|
|
16
|
+
label: Version Confirmation
|
|
17
|
+
description: Please confirm you can reproduce this on a supported version
|
|
18
|
+
options:
|
|
19
|
+
- label: I have confirmed this bug exists on the latest [release](https://github.com/flixOpt/flixopt/releases) of FlixOpt
|
|
20
|
+
required: true
|
|
21
|
+
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: problem
|
|
24
|
+
attributes:
|
|
25
|
+
label: Bug Description
|
|
26
|
+
description: Clearly describe what went wrong
|
|
27
|
+
placeholder: |
|
|
28
|
+
What happened? What did you expect to happen instead?
|
|
29
|
+
|
|
30
|
+
Include any error messages or unexpected outputs.
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: example
|
|
36
|
+
attributes:
|
|
37
|
+
label: Minimal Reproducible Example
|
|
38
|
+
description: |
|
|
39
|
+
Provide the smallest possible code example that reproduces the bug.
|
|
40
|
+
See [how to create minimal bug reports](https://matthewrocklin.com/minimal-bug-reports).
|
|
41
|
+
placeholder: |
|
|
42
|
+
import flixopt as fx
|
|
43
|
+
import pandas as pd
|
|
44
|
+
|
|
45
|
+
# Minimal example that reproduces the bug
|
|
46
|
+
timesteps = pd.date_range('2024-01-01', periods=24, freq='h')
|
|
47
|
+
flow_system = fx.FlowSystem(timesteps)
|
|
48
|
+
|
|
49
|
+
# Add components that trigger the bug...
|
|
50
|
+
|
|
51
|
+
# Show the problematic operation
|
|
52
|
+
result = flow_system.solve() # This should fail/behave unexpectedly
|
|
53
|
+
render: python
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
|
|
57
|
+
- type: textarea
|
|
58
|
+
id: error-output
|
|
59
|
+
attributes:
|
|
60
|
+
label: Error Output
|
|
61
|
+
description: If there's an error message, paste the full traceback here
|
|
62
|
+
render: shell
|
|
63
|
+
|
|
64
|
+
- type: dropdown
|
|
65
|
+
id: solver
|
|
66
|
+
attributes:
|
|
67
|
+
label: Solver Used
|
|
68
|
+
description: Which solver were you using?
|
|
69
|
+
options:
|
|
70
|
+
- HiGHS (default)
|
|
71
|
+
- Gurobi
|
|
72
|
+
- CPLEX
|
|
73
|
+
- GLPK
|
|
74
|
+
- CBC
|
|
75
|
+
- Other (specify below)
|
|
76
|
+
validations:
|
|
77
|
+
required: true
|
|
78
|
+
|
|
79
|
+
- type: input
|
|
80
|
+
id: os
|
|
81
|
+
attributes:
|
|
82
|
+
label: Operating System
|
|
83
|
+
placeholder: "e.g., Windows 11, macOS 14.2, Ubuntu 22.04"
|
|
84
|
+
validations:
|
|
85
|
+
required: true
|
|
86
|
+
|
|
87
|
+
- type: input
|
|
88
|
+
id: python-version
|
|
89
|
+
attributes:
|
|
90
|
+
label: Python Version
|
|
91
|
+
placeholder: "e.g., 3.11.5"
|
|
92
|
+
validations:
|
|
93
|
+
required: true
|
|
94
|
+
|
|
95
|
+
- type: textarea
|
|
96
|
+
id: environment
|
|
97
|
+
attributes:
|
|
98
|
+
label: Environment Info
|
|
99
|
+
description: |
|
|
100
|
+
Run one of these commands and paste the output:
|
|
101
|
+
- `pip freeze`
|
|
102
|
+
- `conda env export`
|
|
103
|
+
render: shell
|
|
104
|
+
value: >
|
|
105
|
+
<details>
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Replace this with your environment info
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
</details>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: 🤔 Modeling Questions
|
|
4
|
+
url: https://github.com/flixOpt/flixopt/discussions/categories/q-a
|
|
5
|
+
about: "How to model specific energy systems, components, and constraints"
|
|
6
|
+
- name: ⚡ Performance & Optimization
|
|
7
|
+
url: https://github.com/flixOpt/flixopt/discussions/categories/performance
|
|
8
|
+
about: "Solver performance, memory usage, and optimization speed issues"
|
|
9
|
+
- name: 💡 Ideas & Suggestions
|
|
10
|
+
url: https://github.com/flixOpt/flixopt/discussions/categories/ideas
|
|
11
|
+
about: "Share ideas and discuss potential improvements with the community"
|
|
12
|
+
- name: 📖 Documentation
|
|
13
|
+
url: https://flixopt.github.io/flixopt/latest/
|
|
14
|
+
about: "Browse guides, API reference, and examples"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
name: ✨ Feature Request
|
|
2
|
+
description: Suggest a new feature or enhancement
|
|
3
|
+
title: "[FEATURE] "
|
|
4
|
+
labels: ["type: feature"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for suggesting a new feature!
|
|
10
|
+
|
|
11
|
+
**Before submitting**: Please search [existing issues](https://github.com/flixOpt/flixopt/issues) and check our [roadmap](https://github.com/flixOpt/flixopt/discussions) to avoid duplicates.
|
|
12
|
+
|
|
13
|
+
- type: checkboxes
|
|
14
|
+
id: checks
|
|
15
|
+
attributes:
|
|
16
|
+
label: Prerequisites
|
|
17
|
+
options:
|
|
18
|
+
- label: I have searched existing issues and discussions
|
|
19
|
+
required: true
|
|
20
|
+
- label: I have checked the [documentation](https://flixopt.github.io/flixopt/latest/)
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: dropdown
|
|
24
|
+
id: feature-type
|
|
25
|
+
attributes:
|
|
26
|
+
label: Feature Category
|
|
27
|
+
description: What type of feature is this?
|
|
28
|
+
options:
|
|
29
|
+
- New Component (storage, generation, conversion, etc.)
|
|
30
|
+
- Enhancement to Existing Component
|
|
31
|
+
- New Optimization Feature
|
|
32
|
+
- Data Input/Output Improvement
|
|
33
|
+
- Results/Visualization Enhancement
|
|
34
|
+
- Performance/Solver Improvement
|
|
35
|
+
- API/Usability Improvement
|
|
36
|
+
- Documentation/Examples
|
|
37
|
+
- Other
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: textarea
|
|
42
|
+
id: problem
|
|
43
|
+
attributes:
|
|
44
|
+
label: Problem Statement
|
|
45
|
+
description: What problem would this feature solve?
|
|
46
|
+
placeholder: |
|
|
47
|
+
Current limitation: "FlixOpt doesn't support [specific energy system component/feature]..."
|
|
48
|
+
|
|
49
|
+
Impact: "This prevents users from modeling [specific scenarios]..."
|
|
50
|
+
|
|
51
|
+
- type: textarea
|
|
52
|
+
id: solution
|
|
53
|
+
attributes:
|
|
54
|
+
label: Proposed Solution
|
|
55
|
+
description: Describe your proposed solution in detail
|
|
56
|
+
placeholder: |
|
|
57
|
+
I propose adding a new component/feature that would...
|
|
58
|
+
|
|
59
|
+
Key capabilities:
|
|
60
|
+
- Feature 1
|
|
61
|
+
- Feature 2
|
|
62
|
+
- Feature 3
|
|
63
|
+
validations:
|
|
64
|
+
required: true
|
|
65
|
+
|
|
66
|
+
- type: textarea
|
|
67
|
+
id: use-case
|
|
68
|
+
attributes:
|
|
69
|
+
label: Use Case & Examples
|
|
70
|
+
description: Provide concrete examples of how this would be used
|
|
71
|
+
placeholder: |
|
|
72
|
+
Real-world scenario: "I'm modeling a microgrid with battery storage and need to..."
|
|
73
|
+
|
|
74
|
+
Specific requirements:
|
|
75
|
+
- Must handle [specific constraint]
|
|
76
|
+
- Should support [specific behavior]
|
|
77
|
+
- Would benefit [specific user group]
|
|
78
|
+
validations:
|
|
79
|
+
required: true
|
|
80
|
+
|
|
81
|
+
- type: textarea
|
|
82
|
+
id: code-example
|
|
83
|
+
attributes:
|
|
84
|
+
label: Desired API (Optional)
|
|
85
|
+
description: Show how you'd like to use this feature
|
|
86
|
+
placeholder: |
|
|
87
|
+
# Example of proposed API
|
|
88
|
+
component = fx.NewComponent(
|
|
89
|
+
label='example',
|
|
90
|
+
parameter1=value1,
|
|
91
|
+
parameter2=value2
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
flow_system.add_component(component)
|
|
95
|
+
render: python
|
|
96
|
+
|
|
97
|
+
- type: textarea
|
|
98
|
+
id: alternatives
|
|
99
|
+
attributes:
|
|
100
|
+
label: Alternatives Considered
|
|
101
|
+
description: What workarounds or alternatives have you tried?
|
|
102
|
+
placeholder: |
|
|
103
|
+
Current workaround: "I'm currently using [existing component] but it doesn't support..."
|
|
104
|
+
|
|
105
|
+
Other approaches considered: "I looked into [alternative] but..."
|
|
106
|
+
|
|
107
|
+
- type: dropdown
|
|
108
|
+
id: priority
|
|
109
|
+
attributes:
|
|
110
|
+
label: Priority/Impact
|
|
111
|
+
description: How important is this feature for your work?
|
|
112
|
+
options:
|
|
113
|
+
- Critical - Blocking important work
|
|
114
|
+
- High - Would significantly improve workflow
|
|
115
|
+
- Medium - Nice to have enhancement
|
|
116
|
+
- Low - Minor improvement
|
|
117
|
+
|
|
118
|
+
- type: textarea
|
|
119
|
+
id: additional-context
|
|
120
|
+
attributes:
|
|
121
|
+
label: Additional Context
|
|
122
|
+
description: References, papers, examples from other tools, etc.
|
|
123
|
+
placeholder: |
|
|
124
|
+
References:
|
|
125
|
+
- Research paper: [Title and link]
|
|
126
|
+
- Similar feature in [other tool]: [description]
|
|
127
|
+
- Industry standard: [description]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: 📝 General Issue
|
|
2
|
+
description: For issues that don't fit the specific templates below
|
|
3
|
+
title: ""
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
**For specific issue types, please use the dedicated templates:**
|
|
9
|
+
- 🐛 **Bug Report** - Something is broken or not working as expected
|
|
10
|
+
- ✨ **Feature Request** - Suggest new functionality
|
|
11
|
+
|
|
12
|
+
**For other topics, consider using Discussions instead:**
|
|
13
|
+
- 🤔 [Modeling Questions](https://github.com/flixOpt/flixopt/discussions/categories/q-a) - How to model specific energy systems
|
|
14
|
+
- ⚡ [Performance Help](https://github.com/flixOpt/flixopt/discussions/categories/performance) - Optimization speed and memory issues
|
|
15
|
+
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: issue-description
|
|
18
|
+
attributes:
|
|
19
|
+
label: Issue Description
|
|
20
|
+
description: Describe your issue, question, or concern
|
|
21
|
+
placeholder: |
|
|
22
|
+
Please describe:
|
|
23
|
+
- What you're trying to accomplish
|
|
24
|
+
- What's not working as expected
|
|
25
|
+
- Any relevant context or background
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: context
|
|
31
|
+
attributes:
|
|
32
|
+
label: Additional Context
|
|
33
|
+
description: Code examples, environment details, error messages, etc.
|
|
34
|
+
placeholder: |
|
|
35
|
+
Optional: Add any relevant details like:
|
|
36
|
+
- Code snippets
|
|
37
|
+
- Error messages
|
|
38
|
+
- Environment info
|
|
39
|
+
- Screenshots
|
|
40
|
+
render: markdown
|
|
@@ -15,6 +15,6 @@ Closes #(issue number)
|
|
|
15
15
|
- [ ] Existing tests still pass
|
|
16
16
|
|
|
17
17
|
## Checklist
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
18
|
+
- [x] My code follows the project style
|
|
19
|
+
- [x] I have updated documentation if needed
|
|
20
|
+
- [x] I have added tests for new functionality (if applicable)
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
name: Python Package CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev] # Added develop branch
|
|
6
|
+
tags:
|
|
7
|
+
- 'v*.*.*' # Trigger on semantic version tags
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main, dev, 'feature/*', 'hotfix/*', 'fix/*']
|
|
10
|
+
types: [opened, synchronize, reopened]
|
|
11
|
+
workflow_dispatch: # Allow manual triggering
|
|
12
|
+
|
|
13
|
+
# Set permissions for security
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
# Cancel previous runs on new push
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
env:
|
|
23
|
+
PYTHON_VERSION: "3.11"
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
lint:
|
|
27
|
+
runs-on: ubuntu-22.04
|
|
28
|
+
steps:
|
|
29
|
+
- name: Check out code
|
|
30
|
+
uses: actions/checkout@v5
|
|
31
|
+
|
|
32
|
+
- name: Set up Python
|
|
33
|
+
uses: actions/setup-python@v6
|
|
34
|
+
with:
|
|
35
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
36
|
+
cache: 'pip'
|
|
37
|
+
cache-dependency-path: |
|
|
38
|
+
pyproject.toml
|
|
39
|
+
|
|
40
|
+
- name: Install Ruff
|
|
41
|
+
run: |
|
|
42
|
+
python -m pip install --upgrade pip
|
|
43
|
+
pip install "ruff==0.9.*"
|
|
44
|
+
ruff --version
|
|
45
|
+
|
|
46
|
+
- name: Run Ruff Linting
|
|
47
|
+
run: |
|
|
48
|
+
echo "::group::Ruff Linting"
|
|
49
|
+
ruff check . --output-format=github
|
|
50
|
+
echo "::endgroup::"
|
|
51
|
+
|
|
52
|
+
- name: Run Ruff Formatting Check
|
|
53
|
+
run: |
|
|
54
|
+
echo "::group::Ruff Formatting"
|
|
55
|
+
ruff format --check --diff .
|
|
56
|
+
echo "::endgroup::"
|
|
57
|
+
|
|
58
|
+
test:
|
|
59
|
+
runs-on: ubuntu-22.04
|
|
60
|
+
timeout-minutes: 30
|
|
61
|
+
needs: lint # Run tests only after linting passes
|
|
62
|
+
strategy:
|
|
63
|
+
fail-fast: false # Continue testing other Python versions if one fails
|
|
64
|
+
matrix:
|
|
65
|
+
python-version: ['3.10', '3.11', '3.12', '3.13']
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- name: Check out code
|
|
69
|
+
uses: actions/checkout@v5
|
|
70
|
+
|
|
71
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
72
|
+
uses: actions/setup-python@v6
|
|
73
|
+
with:
|
|
74
|
+
python-version: ${{ matrix.python-version }}
|
|
75
|
+
cache: 'pip'
|
|
76
|
+
cache-dependency-path: |
|
|
77
|
+
pyproject.toml
|
|
78
|
+
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: |
|
|
81
|
+
python -m pip install --upgrade pip
|
|
82
|
+
pip install .[dev] pytest-xdist
|
|
83
|
+
|
|
84
|
+
- name: Run tests
|
|
85
|
+
run: pytest -v -p no:warnings --numprocesses=auto
|
|
86
|
+
|
|
87
|
+
security:
|
|
88
|
+
name: Security Scan
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
needs: lint
|
|
91
|
+
steps:
|
|
92
|
+
- name: Check out code
|
|
93
|
+
uses: actions/checkout@v5
|
|
94
|
+
|
|
95
|
+
- name: Set up Python
|
|
96
|
+
uses: actions/setup-python@v6
|
|
97
|
+
with:
|
|
98
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
99
|
+
cache: 'pip'
|
|
100
|
+
cache-dependency-path: |
|
|
101
|
+
pyproject.toml
|
|
102
|
+
|
|
103
|
+
- name: Install security tools
|
|
104
|
+
run: |
|
|
105
|
+
python -m pip install --upgrade pip
|
|
106
|
+
pip install bandit[toml]
|
|
107
|
+
|
|
108
|
+
- name: Run Bandit security scan
|
|
109
|
+
run: |
|
|
110
|
+
# Gate on HIGH severity & MEDIUM confidence; produce JSON artifact
|
|
111
|
+
bandit -r flixopt/ -c pyproject.toml -f json -o bandit-report.json -q -lll -ii
|
|
112
|
+
# Human-readable output without affecting job status
|
|
113
|
+
bandit -r flixopt/ -c pyproject.toml -q --exit-zero
|
|
114
|
+
|
|
115
|
+
- name: Upload security reports
|
|
116
|
+
uses: actions/upload-artifact@v4
|
|
117
|
+
if: always()
|
|
118
|
+
with:
|
|
119
|
+
name: security-report
|
|
120
|
+
path: bandit-report.json
|
|
121
|
+
retention-days: 30
|
|
122
|
+
|
|
123
|
+
create-release:
|
|
124
|
+
name: Create GitHub Release
|
|
125
|
+
runs-on: ubuntu-latest
|
|
126
|
+
permissions:
|
|
127
|
+
contents: write
|
|
128
|
+
needs: [lint, test, security]
|
|
129
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
130
|
+
|
|
131
|
+
steps:
|
|
132
|
+
- name: Checkout repository
|
|
133
|
+
uses: actions/checkout@v5
|
|
134
|
+
with:
|
|
135
|
+
fetch-depth: 0
|
|
136
|
+
|
|
137
|
+
- name: Set up Python
|
|
138
|
+
uses: actions/setup-python@v6
|
|
139
|
+
with:
|
|
140
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
141
|
+
|
|
142
|
+
- name: Extract release notes
|
|
143
|
+
run: |
|
|
144
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
145
|
+
echo "Extracting release notes for version: $VERSION"
|
|
146
|
+
python scripts/extract_release_notes.py $VERSION > current_release_notes.md
|
|
147
|
+
|
|
148
|
+
- name: Create GitHub Release
|
|
149
|
+
uses: softprops/action-gh-release@v2
|
|
150
|
+
with:
|
|
151
|
+
body_path: current_release_notes.md
|
|
152
|
+
draft: false
|
|
153
|
+
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
|
|
154
|
+
generate_release_notes: true
|
|
155
|
+
env:
|
|
156
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
157
|
+
|
|
158
|
+
publish-testpypi:
|
|
159
|
+
name: Publish to TestPyPI
|
|
160
|
+
runs-on: ubuntu-22.04
|
|
161
|
+
needs: [test, create-release] # Run after tests and release creation
|
|
162
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # Only on tag push
|
|
163
|
+
environment:
|
|
164
|
+
name: testpypi
|
|
165
|
+
url: https://test.pypi.org/p/flixopt
|
|
166
|
+
|
|
167
|
+
steps:
|
|
168
|
+
- name: Checkout repository
|
|
169
|
+
uses: actions/checkout@v5
|
|
170
|
+
|
|
171
|
+
- name: Set up Python
|
|
172
|
+
uses: actions/setup-python@v6
|
|
173
|
+
with:
|
|
174
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
175
|
+
cache: 'pip'
|
|
176
|
+
cache-dependency-path: |
|
|
177
|
+
pyproject.toml
|
|
178
|
+
|
|
179
|
+
- name: Install dependencies
|
|
180
|
+
run: |
|
|
181
|
+
python -m pip install --upgrade pip
|
|
182
|
+
pip install build setuptools wheel twine
|
|
183
|
+
|
|
184
|
+
- name: Build the distribution
|
|
185
|
+
run: |
|
|
186
|
+
python -m build
|
|
187
|
+
|
|
188
|
+
- name: Upload to TestPyPI
|
|
189
|
+
run: |
|
|
190
|
+
twine upload --repository-url https://test.pypi.org/legacy/ dist/* --verbose
|
|
191
|
+
env:
|
|
192
|
+
TWINE_USERNAME: __token__
|
|
193
|
+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
194
|
+
|
|
195
|
+
- name: Test install from TestPyPI
|
|
196
|
+
run: |
|
|
197
|
+
# Create a temporary environment to test installation
|
|
198
|
+
python -m venv test_env
|
|
199
|
+
source test_env/bin/activate
|
|
200
|
+
# Get project name from pyproject.toml (PEP 621)
|
|
201
|
+
PACKAGE_NAME=$(python - <<'PY'
|
|
202
|
+
import sys, tomllib, pathlib
|
|
203
|
+
data = tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))
|
|
204
|
+
print(data["project"]["name"])
|
|
205
|
+
PY
|
|
206
|
+
)
|
|
207
|
+
# Extract version from git tag
|
|
208
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
209
|
+
# Wait and retry while TestPyPI indexes the package
|
|
210
|
+
INSTALL_SUCCESS=false
|
|
211
|
+
for d in 15 30 60 120 180 360 720 1080; do
|
|
212
|
+
sleep "$d"
|
|
213
|
+
echo "Attempting to install $PACKAGE_NAME==$VERSION from TestPyPI (retry after ${d}s)..."
|
|
214
|
+
# Install specific version and verify it matches
|
|
215
|
+
if pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "$PACKAGE_NAME==$VERSION" && \
|
|
216
|
+
python -c "from importlib.metadata import version; installed = version('$PACKAGE_NAME'); print(f'Installed: {installed}'); assert '$VERSION' == installed"; then
|
|
217
|
+
INSTALL_SUCCESS=true
|
|
218
|
+
break
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
|
|
222
|
+
# Check if installation succeeded
|
|
223
|
+
if [ "$INSTALL_SUCCESS" = "false" ]; then
|
|
224
|
+
echo "ERROR: Failed to install $PACKAGE_NAME==$VERSION from TestPyPI after all retries"
|
|
225
|
+
echo "This could indicate:"
|
|
226
|
+
echo " - TestPyPI indexing issues"
|
|
227
|
+
echo " - Package upload problems"
|
|
228
|
+
echo " - Version mismatch between tag and package"
|
|
229
|
+
exit 1
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# Final success confirmation
|
|
233
|
+
python -c "import flixopt; print('TestPyPI installation successful!')"
|
|
234
|
+
|
|
235
|
+
publish-pypi:
|
|
236
|
+
name: Publish to PyPI
|
|
237
|
+
runs-on: ubuntu-22.04
|
|
238
|
+
needs: [publish-testpypi] # Only run after TestPyPI publish succeeds
|
|
239
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # Only on tag push
|
|
240
|
+
environment:
|
|
241
|
+
name: pypi
|
|
242
|
+
url: https://pypi.org/p/flixopt
|
|
243
|
+
|
|
244
|
+
steps:
|
|
245
|
+
- name: Checkout repository
|
|
246
|
+
uses: actions/checkout@v5
|
|
247
|
+
|
|
248
|
+
- name: Set up Python
|
|
249
|
+
uses: actions/setup-python@v6
|
|
250
|
+
with:
|
|
251
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
252
|
+
cache: 'pip'
|
|
253
|
+
cache-dependency-path: |
|
|
254
|
+
pyproject.toml
|
|
255
|
+
|
|
256
|
+
- name: Install dependencies
|
|
257
|
+
run: |
|
|
258
|
+
python -m pip install --upgrade pip
|
|
259
|
+
pip install build setuptools wheel twine
|
|
260
|
+
|
|
261
|
+
- name: Build the distribution
|
|
262
|
+
run: |
|
|
263
|
+
python -m build
|
|
264
|
+
|
|
265
|
+
- name: Upload to PyPI
|
|
266
|
+
run: |
|
|
267
|
+
twine upload dist/* --verbose
|
|
268
|
+
env:
|
|
269
|
+
TWINE_USERNAME: __token__
|
|
270
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
271
|
+
|
|
272
|
+
- name: Verify PyPI installation
|
|
273
|
+
run: |
|
|
274
|
+
# Create a temporary environment to test installation
|
|
275
|
+
python -m venv prod_test_env
|
|
276
|
+
source prod_test_env/bin/activate
|
|
277
|
+
# Get project name from pyproject.toml (PEP 621)
|
|
278
|
+
PACKAGE_NAME=$(python - <<'PY'
|
|
279
|
+
import sys, tomllib, pathlib
|
|
280
|
+
data = tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))
|
|
281
|
+
print(data["project"]["name"])
|
|
282
|
+
PY
|
|
283
|
+
)
|
|
284
|
+
# Extract version from git tag
|
|
285
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
286
|
+
# Wait and retry while PyPI indexes the package
|
|
287
|
+
INSTALL_SUCCESS=false
|
|
288
|
+
for d in 5 10 15 30 60 120 180 360 720 1080; do
|
|
289
|
+
sleep "$d"
|
|
290
|
+
echo "Attempting to install $PACKAGE_NAME==$VERSION from PyPI (retry after ${d}s)..."
|
|
291
|
+
# Install specific version and verify it matches
|
|
292
|
+
if pip install "$PACKAGE_NAME==$VERSION" && \
|
|
293
|
+
python -c "from importlib.metadata import version; installed = version('$PACKAGE_NAME'); print(f'Installed: {installed}'); assert '$VERSION' == installed"; then
|
|
294
|
+
INSTALL_SUCCESS=true
|
|
295
|
+
break
|
|
296
|
+
fi
|
|
297
|
+
done
|
|
298
|
+
|
|
299
|
+
# Check if installation succeeded
|
|
300
|
+
if [ "$INSTALL_SUCCESS" = "false" ]; then
|
|
301
|
+
echo "ERROR: Failed to install $PACKAGE_NAME==$VERSION from PyPI after all retries"
|
|
302
|
+
echo "This could indicate:"
|
|
303
|
+
echo " - PyPI indexing issues"
|
|
304
|
+
echo " - Package upload problems"
|
|
305
|
+
echo " - Version mismatch between tag and package"
|
|
306
|
+
exit 1
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
# Final success confirmation
|
|
310
|
+
python -c "import flixopt; print('PyPI installation successful!')"
|
|
311
|
+
|
|
312
|
+
deploy-docs:
|
|
313
|
+
name: Deploy Documentation
|
|
314
|
+
runs-on: ubuntu-22.04
|
|
315
|
+
permissions:
|
|
316
|
+
contents: write
|
|
317
|
+
needs: [publish-pypi] # Deploy docs after successful PyPI publishing
|
|
318
|
+
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc')
|
|
319
|
+
|
|
320
|
+
steps:
|
|
321
|
+
- name: Checkout repository
|
|
322
|
+
uses: actions/checkout@v5
|
|
323
|
+
with:
|
|
324
|
+
fetch-depth: 0 # Fetch all history for proper versioning
|
|
325
|
+
|
|
326
|
+
- name: Set up Python
|
|
327
|
+
uses: actions/setup-python@v6
|
|
328
|
+
with:
|
|
329
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
330
|
+
cache: 'pip'
|
|
331
|
+
cache-dependency-path: |
|
|
332
|
+
pyproject.toml
|
|
333
|
+
|
|
334
|
+
- name: Sync changelog to docs
|
|
335
|
+
run: |
|
|
336
|
+
cp CHANGELOG.md docs/changelog.md
|
|
337
|
+
echo "✅ Synced changelog to docs"
|
|
338
|
+
|
|
339
|
+
- name: Install documentation dependencies
|
|
340
|
+
run: |
|
|
341
|
+
python -m pip install --upgrade pip
|
|
342
|
+
pip install -e ".[docs]"
|
|
343
|
+
|
|
344
|
+
- name: Configure Git Credentials
|
|
345
|
+
run: |
|
|
346
|
+
git config user.name github-actions[bot]
|
|
347
|
+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
|
348
|
+
|
|
349
|
+
- name: Deploy docs
|
|
350
|
+
run: |
|
|
351
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
352
|
+
echo "Deploying docs after successful PyPI publish: $VERSION"
|
|
353
|
+
mike deploy --push --update-aliases $VERSION latest
|
|
354
|
+
mike set-default --push latest
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v5.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
exclude: ^mkdocs\.yml$ # Skip mkdocs.yml
|
|
9
|
+
- id: check-added-large-files
|
|
10
|
+
|
|
11
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
12
|
+
rev: v0.12.4
|
|
13
|
+
hooks:
|
|
14
|
+
- id: ruff-check
|
|
15
|
+
args: [ --fix ]
|
|
16
|
+
- id: ruff-format
|