pyoframe 0.1.4__tar.gz → 0.2.0__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.
Files changed (186) hide show
  1. pyoframe-0.2.0/.gitattributes +3 -0
  2. pyoframe-0.2.0/.github/CODEOWNERS +1 -0
  3. pyoframe-0.2.0/.github/actions/setup_optimizers_linux/action.yml +132 -0
  4. pyoframe-0.2.0/.github/actions/setup_optimizers_macos/action.yml +175 -0
  5. pyoframe-0.2.0/.github/actions/setup_optimizers_windows/action.yml +137 -0
  6. pyoframe-0.2.0/.github/workflows/ci.yml +94 -0
  7. pyoframe-0.2.0/.github/workflows/format.yml +16 -0
  8. pyoframe-0.2.0/.github/workflows/lines_changed_counter.yml +49 -0
  9. pyoframe-0.2.0/.github/workflows/lint.yml +13 -0
  10. pyoframe-0.2.0/.github/workflows/publish_doc.yml +33 -0
  11. pyoframe-0.2.0/.github/workflows/publish_to_pypi.yml +33 -0
  12. pyoframe-0.2.0/.gitignore +16 -0
  13. pyoframe-0.2.0/.pre-commit-config.yaml +9 -0
  14. pyoframe-0.2.0/.vscode/settings.json +7 -0
  15. pyoframe-0.2.0/CHANGELOG.md +3 -0
  16. {pyoframe-0.1.4 → pyoframe-0.2.0}/LICENSE +1 -1
  17. {pyoframe-0.1.4/src/pyoframe.egg-info → pyoframe-0.2.0}/PKG-INFO +19 -18
  18. pyoframe-0.2.0/conftest.py +38 -0
  19. pyoframe-0.2.0/docs/SUMMARY.md +4 -0
  20. pyoframe-0.2.0/docs/contribute/index.md +36 -0
  21. pyoframe-0.2.0/docs/index.md +53 -0
  22. pyoframe-0.2.0/docs/learn/01_getting-started/01_installation.md +26 -0
  23. pyoframe-0.2.0/docs/learn/01_getting-started/02_build-simple-model.md +196 -0
  24. pyoframe-0.2.0/docs/learn/01_getting-started/04_building_blocks.md +17 -0
  25. pyoframe-0.2.0/docs/learn/01_getting-started/05_special_functions.md +18 -0
  26. pyoframe-0.2.0/docs/learn/01_getting-started/06_accessing_the_solver.md +40 -0
  27. pyoframe-0.2.0/docs/learn/01_getting-started/SUMMARY.md +5 -0
  28. pyoframe-0.2.0/docs/learn/01_getting-started/inputs/food_data.csv +3 -0
  29. pyoframe-0.2.0/docs/learn/01_getting-started/inputs/foods.csv +4 -0
  30. pyoframe-0.2.0/docs/learn/01_getting-started/inputs/foods_to_nutrients.csv +7 -0
  31. pyoframe-0.2.0/docs/learn/01_getting-started/inputs/nutrients.csv +3 -0
  32. pyoframe-0.2.0/docs/learn/01_getting-started/inputs/results.csv +4 -0
  33. pyoframe-0.2.0/docs/learn/01_getting-started/power_grid_example.ipynb +1559 -0
  34. pyoframe-0.2.0/docs/learn/01_getting-started/three-bus.png +0 -0
  35. pyoframe-0.2.0/docs/learn/02_tutorials/index.md +5 -0
  36. pyoframe-0.2.0/docs/learn/03_concepts/01_pyoframe-datastructure.md +7 -0
  37. pyoframe-0.2.0/docs/learn/03_concepts/02_performance_tips.md +13 -0
  38. pyoframe-0.2.0/docs/learn/03_concepts/03_quadratic_expressions.md +41 -0
  39. pyoframe-0.2.0/docs/learn/03_concepts/04_troubleshooting.md +7 -0
  40. pyoframe-0.2.0/docs/learn/03_concepts/SUMMARY.md +4 -0
  41. pyoframe-0.2.0/docs/learn/04_examples/index.md +8 -0
  42. pyoframe-0.2.0/docs/learn/SUMMARY.md +4 -0
  43. pyoframe-0.2.0/docs/learn/index.md +44 -0
  44. pyoframe-0.2.0/docs/overrides/home.html +4 -0
  45. pyoframe-0.2.0/docs/overrides/partials/actions.html +27 -0
  46. pyoframe-0.2.0/docs/why-pyoframe/SUMMARY.md +5 -0
  47. pyoframe-0.2.0/docs/why-pyoframe/benchmarks.md +0 -0
  48. pyoframe-0.2.0/docs/why-pyoframe/data_py.parquet +0 -0
  49. pyoframe-0.2.0/docs/why-pyoframe/gen_py.parquet +0 -0
  50. pyoframe-0.2.0/docs/why-pyoframe/index.md +14 -0
  51. pyoframe-0.2.0/docs/why-pyoframe/pyoframe-performance.ipynb +602 -0
  52. pyoframe-0.2.0/docs/why-pyoframe/three-bus-four-gen.png +0 -0
  53. pyoframe-0.2.0/docs/why-pyoframe/why-pyoframe.md +1 -0
  54. pyoframe-0.2.0/mkdocs.yml +90 -0
  55. {pyoframe-0.1.4 → pyoframe-0.2.0}/pyproject.toml +19 -16
  56. pyoframe-0.2.0/scripts/gen_ref_pages.py +35 -0
  57. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/__init__.py +5 -0
  58. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/_arithmetic.py +13 -14
  59. pyoframe-0.2.0/src/pyoframe/_version.py +21 -0
  60. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/constants.py +12 -7
  61. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/core.py +169 -72
  62. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/model.py +63 -35
  63. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/model_element.py +3 -4
  64. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/util.py +3 -3
  65. {pyoframe-0.1.4 → pyoframe-0.2.0/src/pyoframe.egg-info}/PKG-INFO +19 -18
  66. pyoframe-0.2.0/src/pyoframe.egg-info/SOURCES.txt +181 -0
  67. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe.egg-info/requires.txt +7 -7
  68. pyoframe-0.2.0/tests/__init__.py +0 -0
  69. pyoframe-0.2.0/tests/conftest.py +19 -0
  70. pyoframe-0.2.0/tests/examples/README.md +10 -0
  71. pyoframe-0.2.0/tests/examples/__init__.py +0 -0
  72. pyoframe-0.2.0/tests/examples/cutting_stock_problem/__init__.py +0 -0
  73. pyoframe-0.2.0/tests/examples/cutting_stock_problem/input_data/orders.csv +14 -0
  74. pyoframe-0.2.0/tests/examples/cutting_stock_problem/input_data/parameters.csv +3 -0
  75. pyoframe-0.2.0/tests/examples/cutting_stock_problem/model.py +36 -0
  76. pyoframe-0.2.0/tests/examples/cutting_stock_problem/results/objective.csv +2 -0
  77. pyoframe-0.2.0/tests/examples/cutting_stock_problem/results/problem-gurobi-machine.lp +75 -0
  78. pyoframe-0.2.0/tests/examples/cutting_stock_problem/results/problem-gurobi-pretty.lp +180 -0
  79. pyoframe-0.2.0/tests/examples/cutting_stock_problem/results/problem-highs-machine.lp +183 -0
  80. pyoframe-0.2.0/tests/examples/cutting_stock_problem/results/problem-highs-pretty.lp +183 -0
  81. pyoframe-0.2.0/tests/examples/diet_problem/README.md +5 -0
  82. pyoframe-0.2.0/tests/examples/diet_problem/__init__.py +0 -0
  83. pyoframe-0.2.0/tests/examples/diet_problem/input_data/foods.csv +10 -0
  84. pyoframe-0.2.0/tests/examples/diet_problem/input_data/foods_to_nutrients.csv +37 -0
  85. pyoframe-0.2.0/tests/examples/diet_problem/input_data/nutrients.csv +5 -0
  86. pyoframe-0.2.0/tests/examples/diet_problem/model.py +42 -0
  87. pyoframe-0.2.0/tests/examples/diet_problem/model_gurobipy.py +56 -0
  88. pyoframe-0.2.0/tests/examples/diet_problem/results/Buy.csv +10 -0
  89. pyoframe-0.2.0/tests/examples/diet_problem/results/Buy_ub.csv +10 -0
  90. pyoframe-0.2.0/tests/examples/diet_problem/results/max_nutrients.csv +4 -0
  91. pyoframe-0.2.0/tests/examples/diet_problem/results/min_nutrients.csv +3 -0
  92. pyoframe-0.2.0/tests/examples/diet_problem/results/objective.csv +2 -0
  93. pyoframe-0.2.0/tests/examples/diet_problem/results/problem-gurobi-machine.lp +28 -0
  94. pyoframe-0.2.0/tests/examples/diet_problem/results/problem-gurobi-pretty.lp +36 -0
  95. pyoframe-0.2.0/tests/examples/diet_problem/results/problem-highs-machine.lp +21 -0
  96. pyoframe-0.2.0/tests/examples/diet_problem/results/problem-highs-pretty.lp +21 -0
  97. pyoframe-0.2.0/tests/examples/diet_problem/results/solution-gurobi-machine.sol +11 -0
  98. pyoframe-0.2.0/tests/examples/diet_problem/results/solution-gurobi-pretty.sol +11 -0
  99. pyoframe-0.2.0/tests/examples/diet_problem/results/solution-highs-machine.sol +69 -0
  100. pyoframe-0.2.0/tests/examples/diet_problem/results/solution-highs-pretty.sol +69 -0
  101. pyoframe-0.2.0/tests/examples/facility_location/__init__.py +0 -0
  102. pyoframe-0.2.0/tests/examples/facility_location/model.py +108 -0
  103. pyoframe-0.2.0/tests/examples/facility_location/results/objective.csv +2 -0
  104. pyoframe-0.2.0/tests/examples/facility_location/results/problem-gurobi-machine.lp +178 -0
  105. pyoframe-0.2.0/tests/examples/facility_location/results/problem-gurobi-pretty.lp +311 -0
  106. pyoframe-0.2.0/tests/examples/facility_problem/__init__.py +0 -0
  107. pyoframe-0.2.0/tests/examples/facility_problem/input_data/plants.csv +6 -0
  108. pyoframe-0.2.0/tests/examples/facility_problem/input_data/transport_costs.csv +5 -0
  109. pyoframe-0.2.0/tests/examples/facility_problem/input_data/wharehouses.csv +5 -0
  110. pyoframe-0.2.0/tests/examples/facility_problem/model.py +40 -0
  111. pyoframe-0.2.0/tests/examples/facility_problem/model_gurobipy.py +71 -0
  112. pyoframe-0.2.0/tests/examples/facility_problem/results/con_max_capacity.csv +6 -0
  113. pyoframe-0.2.0/tests/examples/facility_problem/results/con_meet_demand.csv +5 -0
  114. pyoframe-0.2.0/tests/examples/facility_problem/results/objective.csv +2 -0
  115. pyoframe-0.2.0/tests/examples/facility_problem/results/open.csv +6 -0
  116. pyoframe-0.2.0/tests/examples/facility_problem/results/problem-gurobi-machine.lp +22 -0
  117. pyoframe-0.2.0/tests/examples/facility_problem/results/problem-gurobi-pretty.lp +35 -0
  118. pyoframe-0.2.0/tests/examples/facility_problem/results/problem-highs-machine.lp +29 -0
  119. pyoframe-0.2.0/tests/examples/facility_problem/results/problem-highs-pretty.lp +29 -0
  120. pyoframe-0.2.0/tests/examples/facility_problem/results/solution-gurobi-machine.sol +27 -0
  121. pyoframe-0.2.0/tests/examples/facility_problem/results/solution-gurobi-pretty.sol +27 -0
  122. pyoframe-0.2.0/tests/examples/facility_problem/results/solution-highs-machine.sol +50 -0
  123. pyoframe-0.2.0/tests/examples/facility_problem/results/solution-highs-pretty.sol +50 -0
  124. pyoframe-0.2.0/tests/examples/facility_problem/results/transport.csv +21 -0
  125. pyoframe-0.2.0/tests/examples/production_planning/__init__.py +0 -0
  126. pyoframe-0.2.0/tests/examples/production_planning/input_data/machines_availability.csv +3 -0
  127. pyoframe-0.2.0/tests/examples/production_planning/input_data/processing_times.csv +7 -0
  128. pyoframe-0.2.0/tests/examples/production_planning/input_data/products_profit.csv +4 -0
  129. pyoframe-0.2.0/tests/examples/production_planning/model.py +36 -0
  130. pyoframe-0.2.0/tests/examples/production_planning/results/objective.csv +2 -0
  131. pyoframe-0.2.0/tests/examples/production_planning/results/problem-gurobi-machine.lp +10 -0
  132. pyoframe-0.2.0/tests/examples/production_planning/results/problem-gurobi-pretty.lp +12 -0
  133. pyoframe-0.2.0/tests/examples/production_planning/results/problem-highs-machine.lp +9 -0
  134. pyoframe-0.2.0/tests/examples/production_planning/results/problem-highs-pretty.lp +9 -0
  135. pyoframe-0.2.0/tests/examples/production_planning/results/solution-gurobi-machine.sol +5 -0
  136. pyoframe-0.2.0/tests/examples/production_planning/results/solution-gurobi-pretty.sol +5 -0
  137. pyoframe-0.2.0/tests/examples/production_planning/results/solution-highs-machine.sol +33 -0
  138. pyoframe-0.2.0/tests/examples/production_planning/results/solution-highs-pretty.sol +33 -0
  139. pyoframe-0.2.0/tests/examples/production_planning/results/solution.csv +4 -0
  140. pyoframe-0.2.0/tests/examples/pumped_storage/README.md +8 -0
  141. pyoframe-0.2.0/tests/examples/pumped_storage/__init__.py +0 -0
  142. pyoframe-0.2.0/tests/examples/pumped_storage/input_data/elspot-prices_2021_hourly_eur.csv +8762 -0
  143. pyoframe-0.2.0/tests/examples/pumped_storage/model.py +85 -0
  144. pyoframe-0.2.0/tests/examples/pumped_storage/results/Pump.csv +1461 -0
  145. pyoframe-0.2.0/tests/examples/pumped_storage/results/Storage_level.csv +1461 -0
  146. pyoframe-0.2.0/tests/examples/pumped_storage/results/Turb.csv +1461 -0
  147. pyoframe-0.2.0/tests/examples/pumped_storage/results/initial_storage_level.csv +2 -0
  148. pyoframe-0.2.0/tests/examples/pumped_storage/results/intermediate_storage_level.csv +1461 -0
  149. pyoframe-0.2.0/tests/examples/pumped_storage/results/objective.csv +2 -0
  150. pyoframe-0.2.0/tests/examples/pumped_storage/results/problem-gurobi-machine.lp +6563 -0
  151. pyoframe-0.2.0/tests/examples/pumped_storage/results/problem-gurobi-pretty.lp +18986 -0
  152. pyoframe-0.2.0/tests/examples/pumped_storage/results/problem-highs-machine.lp +8876 -0
  153. pyoframe-0.2.0/tests/examples/pumped_storage/results/problem-highs-pretty.lp +9018 -0
  154. pyoframe-0.2.0/tests/examples/pumped_storage/results/pump_and_turbine_xor.csv +1461 -0
  155. pyoframe-0.2.0/tests/examples/pumped_storage/results/solution-gurobi-machine.sol +4382 -0
  156. pyoframe-0.2.0/tests/examples/pumped_storage/results/solution-gurobi-pretty.sol +4382 -0
  157. pyoframe-0.2.0/tests/examples/pumped_storage/results/solution-highs-machine.sol +7317 -0
  158. pyoframe-0.2.0/tests/examples/pumped_storage/results/solution-highs-pretty.sol +7317 -0
  159. pyoframe-0.2.0/tests/examples/sudoku/__init__.py +0 -0
  160. pyoframe-0.2.0/tests/examples/sudoku/input_data/initial_numbers.csv +22 -0
  161. pyoframe-0.2.0/tests/examples/sudoku/model.py +49 -0
  162. pyoframe-0.2.0/tests/examples/sudoku/results/problem-gurobi-machine.lp +697 -0
  163. pyoframe-0.2.0/tests/examples/sudoku/results/problem-gurobi-pretty.lp +770 -0
  164. pyoframe-0.2.0/tests/examples/sudoku/results/problem-highs-machine.lp +1813 -0
  165. pyoframe-0.2.0/tests/examples/sudoku/results/problem-highs-pretty.lp +1813 -0
  166. pyoframe-0.2.0/tests/examples/sudoku/results/solution-gurobi-machine.sol +731 -0
  167. pyoframe-0.2.0/tests/examples/sudoku/results/solution-gurobi-pretty.sol +731 -0
  168. pyoframe-0.2.0/tests/examples/sudoku/results/solution-highs-machine.sol +1090 -0
  169. pyoframe-0.2.0/tests/examples/sudoku/results/solution-highs-pretty.sol +1090 -0
  170. pyoframe-0.2.0/tests/examples/sudoku/results/solution.csv +10 -0
  171. {pyoframe-0.1.4 → pyoframe-0.2.0}/tests/test_arithmetic.py +13 -17
  172. pyoframe-0.2.0/tests/test_examples.py +243 -0
  173. pyoframe-0.2.0/tests/test_io.py +137 -0
  174. {pyoframe-0.1.4 → pyoframe-0.2.0}/tests/test_model.py +14 -0
  175. {pyoframe-0.1.4 → pyoframe-0.2.0}/tests/test_solver.py +12 -18
  176. pyoframe-0.2.0/tests/util.py +53 -0
  177. pyoframe-0.1.4/src/pyoframe.egg-info/SOURCES.txt +0 -23
  178. pyoframe-0.1.4/tests/test_examples.py +0 -198
  179. pyoframe-0.1.4/tests/test_io.py +0 -75
  180. {pyoframe-0.1.4 → pyoframe-0.2.0}/README.md +0 -0
  181. {pyoframe-0.1.4 → pyoframe-0.2.0}/setup.cfg +0 -0
  182. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/monkey_patch.py +0 -0
  183. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe/objective.py +0 -0
  184. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe.egg-info/dependency_links.txt +0 -0
  185. {pyoframe-0.1.4 → pyoframe-0.2.0}/src/pyoframe.egg-info/top_level.txt +0 -0
  186. {pyoframe-0.1.4 → pyoframe-0.2.0}/tests/test_operations.py +0 -0
@@ -0,0 +1,3 @@
1
+ # This avoids the generated files from showing up in the stats. Note that I don't use 'linguist-generated' because I still want to see the diffs.
2
+ # More info at: https://github.com/github-linguist/linguist/blob/main/docs/overrides.md
3
+ /tests/examples/*/results/* linguist-documentation
@@ -0,0 +1 @@
1
+ * @staadecker
@@ -0,0 +1,132 @@
1
+ # Copyright (c) 2023: Yue Yang
2
+ # Mozilla Public License Version 2.0
3
+ # https://mozilla.org/MPL/2.0/.
4
+
5
+ name: "Install optimizers on linux"
6
+
7
+ inputs:
8
+ GUROBI_WLS:
9
+ description: "..."
10
+ required: true
11
+ # COPT_CLIENT_INI:
12
+ # description: "..."
13
+ # required: true
14
+ # MOSEK_LICENSE:
15
+ # description: "..."
16
+ # required: true
17
+ # GITHUB_TOKEN:
18
+ # description: "..."
19
+ # required: true
20
+ CHECK_LICENSE:
21
+ description: "..."
22
+ required: true
23
+
24
+ runs:
25
+ using: "composite"
26
+ steps:
27
+ - name: Create directory to store installers
28
+ shell: bash
29
+ run: |
30
+ mkdir -p ~/installers
31
+
32
+ - name: Cache Installers
33
+ id: cache-installers-linux
34
+ uses: actions/cache@v4
35
+ env:
36
+ cache-name: cache-installers-linux
37
+ with:
38
+ path: ~/installers
39
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('optimizer_version.toml') }}
40
+ restore-keys: |
41
+ ${{ runner.os }}-build-${{ env.cache-name }}-
42
+
43
+ - if: ${{ steps.cache-installers-linux.outputs.cache-hit != 'true' }}
44
+ shell: bash
45
+ name: Download Installers
46
+ run: |
47
+ curl -L -o ~/installers/gurobi.tar.gz https://packages.gurobi.com/12.0/gurobi12.0.2_linux64.tar.gz
48
+
49
+ - name: Setup Gurobi Installation
50
+ shell: bash
51
+ env:
52
+ GUROBI_WLS: ${{ inputs.GUROBI_WLS }}
53
+ run: |
54
+ tar xfz ~/installers/gurobi.tar.gz -C ~/
55
+ ls ~/gurobi1202/linux64
56
+ # set environment variables
57
+ export GUROBI_HOME="${HOME}/gurobi1202/linux64"
58
+ echo "GUROBI_HOME=${GUROBI_HOME}" >> $GITHUB_ENV
59
+ echo "PATH=${PATH}:${GUROBI_HOME}/bin" >> $GITHUB_ENV
60
+ echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GUROBI_HOME}/lib" >> $GITHUB_ENV
61
+ echo $GUROBI_HOME
62
+
63
+ # setup license using secrets
64
+ echo "$GUROBI_WLS" > ~/gurobi.lic
65
+ echo "GRB_LICENSE_FILE=${HOME}/gurobi.lic" >> $GITHUB_ENV
66
+ - name: Test Gurobi
67
+ if: ${{ inputs.CHECK_LICENSE == 'true' }}
68
+ uses: nick-fields/retry@v3 # wait 30 seconds (5x) if all licenses are already in use
69
+ with:
70
+ max_attempts: 5
71
+ retry_wait_seconds: 30
72
+ timeout_minutes: 1
73
+ command: gurobi_cl
74
+
75
+ # - name: Setup COPT Installation
76
+ # shell: bash
77
+ # env:
78
+ # COPT_CLIENT_INI: ${{ inputs.COPT_CLIENT_INI }}
79
+ # run: |
80
+ # tar xfz ~/installers/copt.tar.gz -C ~/
81
+ # ls ~/copt72
82
+ # # set environment variables
83
+ # export COPT_HOME="${HOME}/copt72"
84
+ # echo "COPT_HOME=${COPT_HOME}" >> $GITHUB_ENV
85
+ # echo "PATH=${PATH}:${COPT_HOME}/bin" >> $GITHUB_ENV
86
+ # echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${COPT_HOME}/lib" >> $GITHUB_ENV
87
+ # echo $COPT_HOME
88
+
89
+ # # Just use the size-limited license
90
+ # # echo "$COPT_CLIENT_INI" > ~/client.ini
91
+ # # echo "COPT_LICENSE_DIR=${HOME}" >> $GITHUB_ENV
92
+ # - name: Test COPT
93
+ # if: ${{ inputs.CHECK_LICENSE == 'true' }}
94
+ # shell: bash
95
+ # run: |
96
+ # copt_cmd -c "quit"
97
+
98
+ # - name: Setup MOSEK Installation
99
+ # shell: bash
100
+ # env:
101
+ # MOSEK_LICENSE: ${{ inputs.MOSEK_LICENSE }}
102
+ # run: |
103
+ # tar jxf ~/installers/mosek.tar.bz2 -C ~/
104
+ # ls ~/mosek
105
+ # # set environment variables
106
+ # export MOSEK_10_2_BINDIR="${HOME}/mosek/10.2/tools/platform/linux64x86/bin"
107
+ # echo "MOSEK_10_2_BINDIR=${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
108
+ # echo "PATH=${PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
109
+ # echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
110
+ # echo $MOSEK_10_2_BINDIR
111
+
112
+ # # setup license using secrets
113
+ # echo "$MOSEK_LICENSE" > ~/mosek.lic
114
+ # echo "MOSEKLM_LICENSE_FILE=${HOME}/mosek.lic" >> $GITHUB_ENV
115
+ # - name: Test MOSEK
116
+ # if: ${{ inputs.CHECK_LICENSE == 'true' }}
117
+ # shell: bash
118
+ # run: |
119
+ # msktestlic
120
+
121
+ # - name: Setup IPOPT Installation
122
+ # shell: bash
123
+ # run: |
124
+ # mkdir -p ~/ipopt
125
+ # tar xfz ~/installers/idaes-solvers.tar.gz -C ~/ipopt
126
+ # echo "PATH=${PATH}:${HOME}/ipopt" >> $GITHUB_ENV
127
+ # echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/ipopt" >> $GITHUB_ENV
128
+ # ls ~/ipopt
129
+ # - name: Test IPOPT
130
+ # shell: bash
131
+ # run: |
132
+ # ipopt -v
@@ -0,0 +1,175 @@
1
+ # Copyright (c) 2023: Yue Yang
2
+ # Mozilla Public License Version 2.0
3
+ # https://mozilla.org/MPL/2.0/.
4
+
5
+ name: "Install optimizers on macOS"
6
+
7
+ inputs:
8
+ GUROBI_WLS:
9
+ description: "..."
10
+ required: true
11
+ COPT_CLIENT_INI:
12
+ description: "..."
13
+ required: true
14
+ MOSEK_LICENSE:
15
+ description: "..."
16
+ required: true
17
+ GITHUB_TOKEN:
18
+ description: "..."
19
+ required: true
20
+ CHECK_LICENSE:
21
+ description: "..."
22
+ required: true
23
+ ARCH:
24
+ description: "..."
25
+ required: true
26
+ type: choice
27
+ default: "X64"
28
+ options:
29
+ - "X64"
30
+ - "ARM64"
31
+
32
+ runs:
33
+ using: "composite"
34
+ steps:
35
+ - name: Create directory to store installers
36
+ shell: bash
37
+ run: |
38
+ mkdir -p ~/installers
39
+
40
+ - name: Cache Installers
41
+ id: cache-installers-macos
42
+ uses: actions/cache@v4
43
+ env:
44
+ cache-name: cache-installers-macos
45
+ with:
46
+ path: ~/installers
47
+ key: ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-${{ hashFiles('optimizer_version.toml') }}
48
+ restore-keys: |
49
+ ${{ runner.os }}-${{ runner.arch }}-build-${{ env.cache-name }}-
50
+
51
+ - if: ${{ steps.cache-installers-macos.outputs.cache-hit != 'true' }}
52
+ shell: bash
53
+ name: Download Universal Installers
54
+ run: |
55
+ curl -L -o ~/installers/gurobi.pkg https://packages.gurobi.com/11.0/gurobi11.0.0_macos_universal2.pkg
56
+ curl -L -o ~/installers/copt.tar.gz https://pub.shanshu.ai/download/copt/7.2.2/osx64/CardinalOptimizer-7.2.2-universal_mac.tar.gz
57
+
58
+ - if: ${{ (steps.cache-installers-macos.outputs.cache-hit != 'true') && (inputs.ARCH == 'X64') }}
59
+ shell: bash
60
+ name: Download X64 Installers
61
+ run: |
62
+ curl -L -o ~/installers/mosek.tar.bz2 https://download.mosek.com/stable/10.2.0/mosektoolsosx64x86.tar.bz2
63
+ curl -L -o ~/installers/idaes-solvers.tar.gz https://github.com/IDAES/idaes-ext/releases/download/3.4.2/idaes-solvers-darwin-x86_64.tar.gz
64
+
65
+ - if: ${{ (steps.cache-installers-macos.outputs.cache-hit != 'true') && (inputs.ARCH == 'ARM64') }}
66
+ shell: bash
67
+ name: Download ARM64 Installers
68
+ run: |
69
+ curl -L -o ~/installers/mosek.tar.bz2 https://download.mosek.com/stable/10.2.0/mosektoolsosxaarch64.tar.bz2
70
+ curl -L -o ~/installers/idaes-solvers.tar.gz https://github.com/IDAES/idaes-ext/releases/download/3.4.2/idaes-solvers-darwin-aarch64.tar.gz
71
+
72
+ - name: Setup Gurobi Installation
73
+ shell: bash
74
+ env:
75
+ GUROBI_WLS: ${{ inputs.GUROBI_WLS }}
76
+ run: |
77
+ pkgutil --expand-full ~/installers/gurobi.pkg ~/gurobi
78
+ ls ~/gurobi
79
+ # set environment variables
80
+ export GUROBI_HOME="${HOME}/gurobi/gurobi11.0.0_macos_universal2.component.pkg/Payload/Library/gurobi1100/macos_universal2"
81
+ echo "GUROBI_HOME=${GUROBI_HOME}" >> $GITHUB_ENV
82
+ echo "PATH=${PATH}:${GUROBI_HOME}/bin" >> $GITHUB_ENV
83
+ echo "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${GUROBI_HOME}/lib" >> $GITHUB_ENV
84
+ echo $GUROBI_HOME
85
+ ls $GUROBI_HOME
86
+
87
+ # setup license using secrets
88
+ echo "$GUROBI_WLS" > ~/gurobi.lic
89
+ echo "GRB_LICENSE_FILE=${HOME}/gurobi.lic" >> $GITHUB_ENV
90
+ - name: Test Gurobi
91
+ if: ${{ inputs.CHECK_LICENSE == 'true' }}
92
+ shell: bash
93
+ run: |
94
+ gurobi_cl
95
+
96
+ - name: Setup COPT Installation
97
+ shell: bash
98
+ env:
99
+ COPT_CLIENT_INI: ${{ inputs.COPT_CLIENT_INI }}
100
+ run: |
101
+ tar xfz ~/installers/copt.tar.gz -C ~/
102
+ ls ~/copt72
103
+ # set environment variables
104
+ export COPT_HOME="${HOME}/copt72"
105
+ echo "COPT_HOME=${COPT_HOME}" >> $GITHUB_ENV
106
+ echo "PATH=${PATH}:${COPT_HOME}/bin" >> $GITHUB_ENV
107
+ echo "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${COPT_HOME}/lib" >> $GITHUB_ENV
108
+ echo $COPT_HOME
109
+ ls $COPT_HOME
110
+
111
+ # Just use the size-limited license
112
+ # echo "$COPT_CLIENT_INI" > ~/client.ini
113
+ # echo "COPT_LICENSE_DIR=${HOME}" >> $GITHUB_ENV
114
+ - name: Test COPT
115
+ if: ${{ inputs.CHECK_LICENSE == 'true' }}
116
+ shell: bash
117
+ run: |
118
+ copt_cmd -c "quit"
119
+
120
+ - name: Setup MOSEK X64 Installation
121
+ if: ${{ inputs.ARCH == 'X64' }}
122
+ shell: bash
123
+ env:
124
+ MOSEK_LICENSE: ${{ inputs.MOSEK_LICENSE }}
125
+ run: |
126
+ tar jxf ~/installers/mosek.tar.bz2 -C ~/
127
+ ls ~/mosek/10.2/tools/platform
128
+ # set environment variables
129
+ export MOSEK_10_2_BINDIR="${HOME}/mosek/10.2/tools/platform/osx64x86/bin"
130
+ echo "MOSEK_10_2_BINDIR=${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
131
+ echo "PATH=${PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
132
+ echo "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
133
+ echo $MOSEK_10_2_BINDIR
134
+ ls $MOSEK_10_2_BINDIR
135
+
136
+ # setup license using secrets
137
+ echo "$MOSEK_LICENSE" > ~/mosek.lic
138
+ echo "MOSEKLM_LICENSE_FILE=${HOME}/mosek.lic" >> $GITHUB_ENV
139
+ - name: Setup MOSEK ARM64 Installation
140
+ if: ${{ inputs.ARCH == 'ARM64' }}
141
+ shell: bash
142
+ env:
143
+ MOSEK_LICENSE: ${{ inputs.MOSEK_LICENSE }}
144
+ run: |
145
+ tar jxf ~/installers/mosek.tar.bz2 -C ~/
146
+ ls ~/mosek/10.2/tools/platform
147
+ # set environment variables
148
+ export MOSEK_10_2_BINDIR="${HOME}/mosek/10.2/tools/platform/osxaarch64/bin"
149
+ echo "MOSEK_10_2_BINDIR=${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
150
+ echo "PATH=${PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
151
+ echo "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${MOSEK_10_2_BINDIR}" >> $GITHUB_ENV
152
+ echo $MOSEK_10_2_BINDIR
153
+ ls $MOSEK_10_2_BINDIR
154
+
155
+ # setup license using secrets
156
+ echo "$MOSEK_LICENSE" > ~/mosek.lic
157
+ echo "MOSEKLM_LICENSE_FILE=${HOME}/mosek.lic" >> $GITHUB_ENV
158
+ - name: Test MOSEK
159
+ if: ${{ inputs.CHECK_LICENSE == 'true' }}
160
+ shell: bash
161
+ run: |
162
+ msktestlic
163
+
164
+ - name: Setup IPOPT Installation
165
+ shell: bash
166
+ run: |
167
+ mkdir -p ~/ipopt
168
+ tar xfz ~/installers/idaes-solvers.tar.gz -C ~/ipopt
169
+ echo "PATH=${PATH}:${HOME}/ipopt" >> $GITHUB_ENV
170
+ echo "DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${HOME}/ipopt" >> $GITHUB_ENV
171
+ ls ~/ipopt
172
+ - name: Test IPOPT
173
+ shell: bash
174
+ run: |
175
+ ipopt -v
@@ -0,0 +1,137 @@
1
+ # Copyright (c) 2023: Yue Yang
2
+ # Mozilla Public License Version 2.0
3
+ # https://mozilla.org/MPL/2.0/.
4
+
5
+ name: "Install optimizers on windows"
6
+
7
+ inputs:
8
+ GUROBI_WLS:
9
+ description: "..."
10
+ required: true
11
+ # COPT_CLIENT_INI:
12
+ # description: "..."
13
+ # required: true
14
+ # MOSEK_LICENSE:
15
+ # description: "..."
16
+ # required: true
17
+ # GITHUB_TOKEN:
18
+ # description: "..."
19
+ # required: true
20
+ CHECK_LICENSE:
21
+ description: "..."
22
+ required: true
23
+
24
+ runs:
25
+ using: "composite"
26
+ steps:
27
+ - name: Install lessmsi
28
+ shell: pwsh
29
+ run: |
30
+ curl -L -o D:\lessmsi.zip https://github.com/activescott/lessmsi/releases/download/v1.10.0/lessmsi-v1.10.0.zip
31
+ 7z x D:\lessmsi.zip -oD:\lessmsi
32
+ echo "PATH=$env:PATH;D:\lessmsi" >> $env:GITHUB_ENV
33
+ - name: Test lessmsi
34
+ shell: pwsh
35
+ run: |
36
+ lessmsi h
37
+
38
+ - name: Create directory to store installers
39
+ shell: pwsh
40
+ run: |
41
+ New-Item -ItemType Directory -Force -Path "D:\installers"
42
+
43
+ - name: Cache Installers
44
+ id: cache-installers-windows
45
+ uses: actions/cache@v4
46
+ env:
47
+ cache-name: cache-installers-windows
48
+ with:
49
+ path: D:\installers
50
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('optimizer_version.toml') }}
51
+ restore-keys: |
52
+ ${{ runner.os }}-build-${{ env.cache-name }}-
53
+
54
+ - if: ${{ steps.cache-installers-windows.outputs.cache-hit != 'true' }}
55
+ shell: pwsh
56
+ name: Download Installers
57
+ run: |
58
+ curl -L -o D:\installers\gurobi.msi https://packages.gurobi.com/11.0/Gurobi-11.0.0-win64.msi
59
+
60
+ - name: Setup Gurobi Installation
61
+ shell: pwsh
62
+ env:
63
+ GUROBI_WLS: ${{ inputs.GUROBI_WLS }}
64
+ run: |
65
+ lessmsi x D:\installers\gurobi.msi "D:\" gurobi_cl.exe
66
+ lessmsi x D:\installers\gurobi.msi "D:\" gurobi110.dll gurobi110.lib
67
+ lessmsi x D:\installers\gurobi.msi "D:\" gurobi_c.h
68
+ ls D:\SourceDir\gurobi1100\win64
69
+ # set environment variables
70
+ echo "GUROBI_HOME=D:\SourceDir\gurobi1100\win64" >> $env:GITHUB_ENV
71
+ echo "PATH=$env:PATH;D:\SourceDir\gurobi1100\win64\bin" >> $env:GITHUB_ENV
72
+ echo $env:GUROBI_HOME
73
+
74
+ # setup license using secrets
75
+ echo $env:GUROBI_WLS > D:\gurobi.lic
76
+ echo "GRB_LICENSE_FILE=D:\gurobi.lic" >> $env:GITHUB_ENV
77
+ - name: Test Gurobi
78
+ if: ${{ inputs.CHECK_LICENSE == 'true' }}
79
+ shell: pwsh
80
+ run: |
81
+ gurobi_cl
82
+
83
+ # - name: Setup COPT Installation
84
+ # shell: pwsh
85
+ # env:
86
+ # COPT_CLIENT_INI: ${{ inputs.COPT_CLIENT_INI }}
87
+ # run: |
88
+ # # unzip with 7zip
89
+ # 7z x D:\installers\copt.zip -oD:\
90
+ # ls D:\copt72
91
+ # # set environment variables
92
+ # echo "COPT_HOME=D:\copt72" >> $env:GITHUB_ENV
93
+ # echo "PATH=$env:PATH;D:\copt72\bin" >> $env:GITHUB_ENV
94
+ # echo $env:COPT_HOME
95
+
96
+ # # Just use the size-limited license
97
+ # # echo $env:COPT_CLIENT_INI > D:\client.ini
98
+ # # echo "COPT_LICENSE_DIR=D:\" >> $env:GITHUB_ENV
99
+ # - name: Test COPT
100
+ # if: ${{ inputs.CHECK_LICENSE == 'true' }}
101
+ # shell: pwsh
102
+ # run: |
103
+ # copt_cmd -c "quit"
104
+
105
+ # - name: Setup MOSEK Installation
106
+ # shell: pwsh
107
+ # env:
108
+ # MOSEK_LICENSE: ${{ inputs.MOSEK_LICENSE }}
109
+ # run: |
110
+ # lessmsi x D:\installers\mosek.msi "D:\" msktestlic.exe
111
+ # lessmsi x D:\installers\mosek.msi "D:\" mosek64_10_2.dll mosek64_10_2.lib tbb12.dll svml_dispmd.dll
112
+ # lessmsi x D:\installers\mosek.msi "D:\" mosek.h
113
+ # ls D:\SourceDir\PFiles\Mosek\10.2\tools\platform\win64x86
114
+ # # set environment variables
115
+ # echo "MOSEK_10_2_BINDIR=D:\SourceDir\PFiles\Mosek\10.2\tools\platform\win64x86\bin" >> $env:GITHUB_ENV
116
+ # echo "PATH=$env:PATH;D:\SourceDir\PFiles\Mosek\10.2\tools\platform\win64x86\bin" >> $env:GITHUB_ENV
117
+ # echo $env:MOSEK_10_2_BINDIR
118
+
119
+ # # setup license using secrets
120
+ # echo $env:MOSEK_LICENSE > D:\mosek.lic
121
+ # echo "MOSEKLM_LICENSE_FILE=D:\mosek.lic" >> $env:GITHUB_ENV
122
+ # - name: Test MOSEK
123
+ # if: ${{ inputs.CHECK_LICENSE == 'true' }}
124
+ # shell: pwsh
125
+ # run: |
126
+ # msktestlic
127
+
128
+ # - name: Setup IPOPT solver
129
+ # shell: pwsh
130
+ # run: |
131
+ # 7z x -so D:\installers\idaes-solvers.tar.gz | 7z x -si -ttar -oD:\ipopt
132
+ # echo "PATH=D:\ipopt;$env:PATH" >> $env:GITHUB_ENV
133
+ # ls D:\ipopt
134
+ # - name: Test IPOPT
135
+ # shell: pwsh
136
+ # run: |
137
+ # ipopt -v
@@ -0,0 +1,94 @@
1
+ # Note: We use the insecure pull_request_target to allow running workflows from forks.
2
+ # However, we've added checks (see below) for safety.
3
+ # In short, the 'safe to test' label must exist AND the workflow must be run by someone with write access.
4
+ # See more details here:
5
+ # - https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
6
+ # - https://michaelheap.com/access-secrets-from-forks/
7
+ name: Tests
8
+ on:
9
+ push:
10
+ branches: [main]
11
+ pull_request:
12
+ branches: ["*"]
13
+ pull_request_target:
14
+ branches: ["*"]
15
+ schedule:
16
+ - cron: "0 5 * * WED"
17
+ workflow_dispatch:
18
+
19
+ jobs:
20
+ check_permissions:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ # Important checks to ensure that the user has the required permissions. See note above.
24
+ # Step 1: If user has current permissions we're good!
25
+ - name: Get User Permission
26
+ id: checkAccess
27
+ uses: actions-cool/check-user-permission@v2
28
+ with:
29
+ require: write
30
+ username: ${{ github.actor }}
31
+ env:
32
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33
+ # Otherwise, get triggering user's permissions
34
+ - name: Get Triggering User Permission
35
+ if: steps.checkAccess.outputs.require-result == 'false'
36
+ id: checkTriggeringAccess
37
+ uses: actions-cool/check-user-permission@v2
38
+ with:
39
+ require: write
40
+ username: ${{ github.triggering_actor }}
41
+ env:
42
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43
+ # If neither has permissions and no 'safe to test' label throw error
44
+ - name: Check User Permission
45
+ if: steps.checkAccess.outputs.require-result == 'false' && steps.checkTriggeringAccess.outputs.require-result == 'false' && !contains(github.event.pull_request.labels.*.name, 'safe to test')
46
+ shell: bash
47
+ run: |
48
+ echo "${{ github.triggering_actor }} does not have permissions on this repo."
49
+ echo "Re-run the test yourself if you have write permissions. Alternatively, add the label 'safe to test' to the PR to give the user write permissions (only if you trust them)."
50
+ exit 1
51
+ run:
52
+ if: |
53
+ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
54
+ (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) ||
55
+ (github.event_name != 'pull_request_target' && github.event_name != 'pull_request')
56
+ runs-on: ubuntu-latest
57
+ needs: check_permissions
58
+ continue-on-error: ${{ !matrix.latest }}
59
+ strategy:
60
+ fail-fast: true
61
+ matrix:
62
+ python-version: ["3.13"]
63
+ latest: [true]
64
+ include:
65
+ - python-version: "3.9"
66
+ latest: false
67
+ steps:
68
+ - name: Checkout
69
+ uses: actions/checkout@v4
70
+ with:
71
+ fetch-depth: 0
72
+ ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
73
+ - name: Set up Python ${{ matrix.python-version }}
74
+ uses: actions/setup-python@v5
75
+ with:
76
+ python-version: ${{ matrix.python-version }}
77
+ cache: "pip"
78
+ - uses: ./.github/actions/setup_optimizers_linux
79
+ with:
80
+ GUROBI_WLS: ${{ secrets.GUROBI_WLS }}
81
+ CHECK_LICENSE: true
82
+ - name: Install dependencies
83
+ run: |
84
+ pip install --editable .[dev]
85
+ - name: Run tests and collect coverage
86
+ run: pytest --cov
87
+ - name: Upload coverage to Codecov
88
+ uses: codecov/codecov-action@v4-beta
89
+ with:
90
+ name: coverage-python-${{ matrix.python-version }}
91
+ flags: smart-tests
92
+ verbose: true
93
+ env:
94
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -0,0 +1,16 @@
1
+ name: Check formatting with Ruff
2
+
3
+ on: [pull_request]
4
+
5
+ env:
6
+ INPUT_JUPYTER: true
7
+
8
+ jobs:
9
+ format:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/ruff-action@v3
14
+ with:
15
+ args: "format --check --diff"
16
+
@@ -0,0 +1,49 @@
1
+ # MIT License
2
+ # Copyright (c) 2021 Viacheslav Poturaev
3
+ name: Comment on PR with lines changed
4
+ on:
5
+ pull_request:
6
+
7
+ # Cancel the workflow in progress in newer build is about to start.
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ line-count:
14
+ runs-on: ubuntu-latest
15
+
16
+ permissions:
17
+ pull-requests: write
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v2
22
+ with:
23
+ path: pr
24
+ - name: Checkout base code
25
+ uses: actions/checkout@v2
26
+ with:
27
+ ref: ${{ github.event.pull_request.base.sha }}
28
+ path: base
29
+ - name: Count Lines Of Code
30
+ id: loc
31
+ run: |
32
+ curl -sLO https://github.com/vearutop/sccdiff/releases/download/v1.0.3/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz
33
+ sccdiff_hash=$(git hash-object ./sccdiff)
34
+ [ "$sccdiff_hash" == "ae8a07b687bd3dba60861584efe724351aa7ff63" ] || (echo "::error::unexpected hash for sccdiff, possible tampering: $sccdiff_hash" && exit 1)
35
+ OUTPUT=$(cd pr && ../sccdiff -basedir ../base)
36
+ echo "${OUTPUT}"
37
+ OUTPUT="${OUTPUT//$'\n'/%0A}"
38
+ echo "::set-output name=diff::$OUTPUT"
39
+
40
+ - name: Comment Code Lines
41
+ continue-on-error: true
42
+ uses: marocchino/sticky-pull-request-comment@v2
43
+ with:
44
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45
+ header: LOC
46
+ message: |
47
+ ### Lines Of Code
48
+
49
+ ${{ steps.loc.outputs.diff }}
@@ -0,0 +1,13 @@
1
+ name: Check linting with Ruff
2
+ on: [pull_request]
3
+
4
+ env:
5
+ INPUT_JUPYTER: true
6
+
7
+ jobs:
8
+ lint:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: astral-sh/ruff-action@v3 # Default is linter
13
+
@@ -0,0 +1,33 @@
1
+ name: Docs
2
+ on:
3
+ release:
4
+ types: [published]
5
+ env:
6
+ ENABLED_GIT_REVISION_DATE: true
7
+ ENABLED_GIT_COMMITTERS: true
8
+ permissions:
9
+ contents: write
10
+ jobs:
11
+ deploy:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0 # Needed for git-revision-date-localized plugin
17
+ - name: Configure Git Credentials
18
+ run: |
19
+ git config user.name github-actions[bot]
20
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: 3.x
24
+ cache: 'pip'
25
+ - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
26
+ - uses: actions/cache@v4
27
+ with:
28
+ key: mkdocs-material-${{ env.cache_id }}
29
+ path: .cache
30
+ restore-keys: |
31
+ mkdocs-material-
32
+ - run: pip install .[docs]
33
+ - run: mkdocs gh-deploy --force