mirror of
https://github.com/PaiGramTeam/python-genshin-artifact.git
synced 2024-12-11 21:37:34 +00:00
✨ update to PyO3 0.22, add 3.13 support
Co-authored-by: kotoriのねこ <minamiktr@outlook.com>
This commit is contained in:
parent
d8117b36b2
commit
68bef8ce3d
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@ -68,7 +68,7 @@ jobs:
|
|||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]
|
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@ -109,7 +109,7 @@ jobs:
|
|||||||
rust-toolchain: nightly
|
rust-toolchain: nightly
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
manylinux: auto
|
manylinux: auto
|
||||||
args: --release --out dist --interpreter 3.8 3.9 3.10 3.11 3.12
|
args: --release --out dist --interpreter 3.8 3.9 3.10 3.11 3.12 3.13
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
@ -24,7 +24,10 @@ name = "_python_genshin_artifact"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = { version = "0.20.3", features = ["anyhow"] }
|
# TODO it would be very nice to remove the "py-clone" feature as it can panic,
|
||||||
|
# but needs a bit of work to make sure it's not used in the codebase
|
||||||
|
# see https://pyo3.rs/v0.23.3/migration.html#pyclone-is-now-gated-behind-the-py-clone-feature
|
||||||
|
pyo3 = { version = "0.23", features = ["anyhow", "py-clone"] }
|
||||||
mona_wasm = { path = "genshin_artifact/mona_wasm" }
|
mona_wasm = { path = "genshin_artifact/mona_wasm" }
|
||||||
mona = { path = "genshin_artifact/mona_core" }
|
mona = { path = "genshin_artifact/mona_core" }
|
||||||
mona_generate = { path = "genshin_artifact/mona_generate" }
|
mona_generate = { path = "genshin_artifact/mona_generate" }
|
||||||
@ -32,7 +35,7 @@ num = "0.4"
|
|||||||
serde="1.0"
|
serde="1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
pythonize = "0.20.0"
|
pythonize = "0.23"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
69
docs/PyO3_v0.23.0_upgrade.md
Normal file
69
docs/PyO3_v0.23.0_upgrade.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# PyO3 v0.23.0 Upgrade
|
||||||
|
|
||||||
|
## Phase out the usage of GIL-refs
|
||||||
|
|
||||||
|
According to the PyO3 0.21.0 relase note,
|
||||||
|
|
||||||
|
> This release introduces a substantial new direction for PyO3's API. The `Bound<'py, T>` smart pointer type
|
||||||
|
> has been added that replaces "GIL Refs" such as `&'py PyAny` and `&'py PyList` with smart-pointer forms
|
||||||
|
> `Bound<'py, PyAny>` and `Bound<'py, PyList>`. This new smart pointer brings ownership out of PyO3's internals
|
||||||
|
> and into user control. This has been done for sake of both performance and soundness.
|
||||||
|
|
||||||
|
Thus, the usage of `.as_ref(py)` needs to be phased out and replaced by `.bind(py)`:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
||||||
|
- let set_name = self.set_name.as_ref(py).to_str()?;
|
||||||
|
- let slot = self.slot.as_ref(py).to_str()?;
|
||||||
|
- let main_stat = self.main_stat.0.as_ref(py).to_str()?;
|
||||||
|
+ let set_name = self.set_name.bind(py).to_str()?;
|
||||||
|
+ let slot = self.slot.bind(py).to_str()?;
|
||||||
|
+ let main_stat = self.main_stat.0.bind(py).to_str()?;
|
||||||
|
let main_stat_value = self.main_stat.1;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use `Bound<T>` in method arguments and return type
|
||||||
|
|
||||||
|
Explicitly use `Bound<'py, T>` in the return type of `__dict__`:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
#[getter]
|
||||||
|
- pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
||||||
|
+ pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
|
let dict = PyDict::new(py);
|
||||||
|
- let name_str = self.name.as_ref(py).to_str()?;
|
||||||
|
+ let name_str = self.name.bind(py).to_str()?;
|
||||||
|
dict.set_item("name", name_str)?;
|
||||||
|
if let Some(config) = &self.config {
|
||||||
|
- dict.set_item("config", config.as_ref(py))?;
|
||||||
|
+ dict.set_item("config", config.bind(py))?;
|
||||||
|
} else {
|
||||||
|
dict.set_item("config", py.None())?;
|
||||||
|
}
|
||||||
|
- Ok(dict.into())
|
||||||
|
+ Ok(dict)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Also apply `Bound<T>` to method argument:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- a/src/lib.rs
|
||||||
|
+++ b/src/lib.rs
|
||||||
|
@@ -25,7 +25,7 @@ use crate::applications::output::transformative_damage::PyTransformativeDamage;
|
||||||
|
import_exception!(json, JSONDecodeError);
|
||||||
|
|
||||||
|
#[pymodule]
|
||||||
|
-fn _python_genshin_artifact(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
+fn _python_genshin_artifact(py: Python<'_>, m: &Bound<PyModule>) -> PyResult<()> {
|
||||||
|
m.add("JSONDecodeError", py.get_type::<JSONDecodeError>())?;
|
||||||
|
m.add_function(wrap_pyfunction!(get_damage_analysis, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(get_transformative_damage, m)?)?;
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [PyO3 Migration Guide](https://pyo3.rs/v0.23.0/migration.html#from-020-to-021)
|
||||||
|
- [pydantic-core#1222 - Upgrade to PyO3 0.21 beta](https://github.com/pydantic/pydantic-core/pull/1222/files#diff-2e9d962a08321605940b5a657135052fbcef87b5e360662bb527c96d9a615542)
|
||||||
|
- [pydantic-core#1556 - Upgrade to PyO3 0.23 (minimal)](https://github.com/pydantic/pydantic-core/pull/1556/files)
|
||||||
|
- [pydantic-core#1450 - Upgrade to PyO3 0.23 head (WIP)](https://github.com/pydantic/pydantic-core/pull/1450/files)
|
@ -18,6 +18,7 @@ classifiers = [
|
|||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
|
'Programming Language :: Python :: 3.13',
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"Intended Audience :: Information Technology",
|
"Intended Audience :: Information Technology",
|
||||||
"Intended Audience :: System Administrators",
|
"Intended Audience :: System Administrators",
|
||||||
|
@ -43,7 +43,7 @@ pub fn get_damage_analysis(calculator_config: PyCalculatorConfig) -> PyResult<Py
|
|||||||
let artifact_config_interface: Option<ArtifactConfigInterface> =
|
let artifact_config_interface: Option<ArtifactConfigInterface> =
|
||||||
if let Some(artifact_config) = calculator_config.artifact_config {
|
if let Some(artifact_config) = calculator_config.artifact_config {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
depythonize(artifact_config.as_ref(py))
|
depythonize(artifact_config.bind(py))
|
||||||
.map_err(|err| anyhow!("Failed to deserialize artifact config: {}", err))
|
.map_err(|err| anyhow!("Failed to deserialize artifact config: {}", err))
|
||||||
})?
|
})?
|
||||||
} else {
|
} else {
|
||||||
@ -117,7 +117,7 @@ pub fn get_transformative_damage(
|
|||||||
let artifact_config_interface: Option<ArtifactConfigInterface> =
|
let artifact_config_interface: Option<ArtifactConfigInterface> =
|
||||||
if let Some(artifact_config) = calculator_config.artifact_config {
|
if let Some(artifact_config) = calculator_config.artifact_config {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
depythonize(artifact_config.as_ref(py))
|
depythonize(artifact_config.bind(py))
|
||||||
.map_err(|err| anyhow!("Failed to deserialize artifact config: {}", err))
|
.map_err(|err| anyhow!("Failed to deserialize artifact config: {}", err))
|
||||||
})?
|
})?
|
||||||
} else {
|
} else {
|
||||||
|
@ -50,9 +50,9 @@ impl PyArtifact {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
||||||
let set_name = self.set_name.as_ref(py).to_str()?;
|
let set_name = self.set_name.bind(py).to_str()?;
|
||||||
let slot = self.slot.as_ref(py).to_str()?;
|
let slot = self.slot.bind(py).to_str()?;
|
||||||
let main_stat = self.main_stat.0.as_ref(py).to_str()?;
|
let main_stat = self.main_stat.0.bind(py).to_str()?;
|
||||||
let main_stat_value = self.main_stat.1;
|
let main_stat_value = self.main_stat.1;
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"PyArtifact(set_name='{}', slot='{}', level={}, star={}, main_stat=({}, {}), id={})",
|
"PyArtifact(set_name='{}', slot='{}', level={}, star={}, main_stat=({}, {}), id={})",
|
||||||
@ -61,25 +61,25 @@ impl PyArtifact {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("set_name", self.set_name.as_ref(py))?;
|
dict.set_item("set_name", self.set_name.bind(py))?;
|
||||||
dict.set_item("slot", self.slot.as_ref(py))?;
|
dict.set_item("slot", self.slot.bind(py))?;
|
||||||
dict.set_item("level", self.level)?;
|
dict.set_item("level", self.level)?;
|
||||||
dict.set_item("star", self.star)?;
|
dict.set_item("star", self.star)?;
|
||||||
let sub_stats_pylist = PyList::new(
|
let sub_stats_pylist = PyList::new(
|
||||||
py,
|
py,
|
||||||
self.sub_stats.iter().map(|(s, v)| {
|
self.sub_stats.iter().map(|(s, v)| {
|
||||||
let stat_str = s.as_ref(py).to_str().unwrap();
|
let stat_str = s.bind(py).to_str().unwrap();
|
||||||
(stat_str, *v)
|
(stat_str, *v)
|
||||||
}),
|
}),
|
||||||
);
|
)?;
|
||||||
dict.set_item("sub_stats", sub_stats_pylist)?;
|
dict.set_item("sub_stats", sub_stats_pylist)?;
|
||||||
let main_stat_tuple = (self.main_stat.0.as_ref(py), self.main_stat.1);
|
let main_stat_tuple = (self.main_stat.0.bind(py), self.main_stat.1);
|
||||||
dict.set_item("main_stat", main_stat_tuple)?;
|
dict.set_item("main_stat", main_stat_tuple)?;
|
||||||
dict.set_item("id", self.id)?;
|
dict.set_item("id", self.id)?;
|
||||||
|
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ impl TryInto<MonaArtifact> for PyArtifact {
|
|||||||
|
|
||||||
fn try_into(self) -> Result<MonaArtifact, Self::Error> {
|
fn try_into(self) -> Result<MonaArtifact, Self::Error> {
|
||||||
let name: ArtifactSetName = Python::with_gil(|py| {
|
let name: ArtifactSetName = Python::with_gil(|py| {
|
||||||
let _string: &PyString = self.set_name.as_ref(py);
|
let _string: &Bound<'_, PyString> = self.set_name.bind(py);
|
||||||
depythonize(_string).map_err(|err| {
|
depythonize(_string).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _string);
|
let serialized_data = format!("{:?}", _string);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -100,7 +100,7 @@ impl TryInto<MonaArtifact> for PyArtifact {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let slot: ArtifactSlotName = Python::with_gil(|py| {
|
let slot: ArtifactSlotName = Python::with_gil(|py| {
|
||||||
let _string: &PyString = self.slot.as_ref(py);
|
let _string: &Bound<'_, PyString> = self.slot.bind(py);
|
||||||
depythonize(_string).map_err(|err| {
|
depythonize(_string).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _string);
|
let serialized_data = format!("{:?}", _string);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -112,8 +112,8 @@ impl TryInto<MonaArtifact> for PyArtifact {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let main_stat_name: StatName = Python::with_gil(|py| {
|
let main_stat_name: StatName = Python::with_gil(|py| {
|
||||||
let main_stat = self.main_stat.0.as_ref(py);
|
let main_stat = self.main_stat.0.bind(py);
|
||||||
depythonize(self.main_stat.0.as_ref(py)).map_err(|err| {
|
depythonize(self.main_stat.0.bind(py)).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", main_stat);
|
let serialized_data = format!("{:?}", main_stat);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to deserialize main stat into mona::artifacts::StatName: {}. Serialized data: \n{}",
|
"Failed to deserialize main stat into mona::artifacts::StatName: {}. Serialized data: \n{}",
|
||||||
@ -127,8 +127,8 @@ impl TryInto<MonaArtifact> for PyArtifact {
|
|||||||
self.sub_stats
|
self.sub_stats
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
let sub_stats = s.0.as_ref(py);
|
let sub_stats = s.0.bind(py);
|
||||||
let name: Result<StatName, anyhow::Error> = depythonize(s.0.as_ref(py)).map_err(|err| {
|
let name: Result<StatName, anyhow::Error> = depythonize(s.0.bind(py)).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", sub_stats);
|
let serialized_data = format!("{:?}", sub_stats);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to deserialize sub stats into mona::artifacts::StatName: {}. Serialized data: \n{}",
|
"Failed to deserialize sub stats into mona::artifacts::StatName: {}. Serialized data: \n{}",
|
||||||
@ -166,7 +166,8 @@ mod tests {
|
|||||||
pyo3::prepare_freethreaded_python();
|
pyo3::prepare_freethreaded_python();
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let module = PyModule::import(py, "python_genshin_artifact.enka.artifacts")?;
|
let module = PyModule::import(py, "python_genshin_artifact.enka.artifacts")?;
|
||||||
let artifacts_name_map = module.getattr("artifacts_name_map")?.downcast::<PyDict>()?;
|
let artifacts_name_map = module.getattr("artifacts_name_map")?;
|
||||||
|
let artifacts_name_map = artifacts_name_map.downcast::<PyDict>()?;
|
||||||
for (_, value) in artifacts_name_map.iter() {
|
for (_, value) in artifacts_name_map.iter() {
|
||||||
let artifacts_name_str = value.extract::<String>()?;
|
let artifacts_name_str = value.extract::<String>()?;
|
||||||
let res: Result<ArtifactSetName, anyhow::Error> = depythonize(&value).context(
|
let res: Result<ArtifactSetName, anyhow::Error> = depythonize(&value).context(
|
||||||
|
@ -21,14 +21,15 @@ pub struct PyBuffInterface {
|
|||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyBuffInterface {
|
impl PyBuffInterface {
|
||||||
#[new]
|
#[new]
|
||||||
|
#[pyo3(signature = (name, config=None))]
|
||||||
pub fn py_new(name: Py<PyString>, config: Option<Py<PyDict>>) -> PyResult<Self> {
|
pub fn py_new(name: Py<PyString>, config: Option<Py<PyDict>>) -> PyResult<Self> {
|
||||||
Ok(Self { name, config })
|
Ok(Self { name, config })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
||||||
let name = self.name.as_ref(py).to_str()?;
|
let name = self.name.bind(py).to_str()?;
|
||||||
let config_repr = match &self.config {
|
let config_repr = match &self.config {
|
||||||
Some(config) => config.as_ref(py).repr()?.to_str()?.to_string(),
|
Some(config) => config.bind(py).repr()?.to_str()?.to_string(),
|
||||||
None => "None".to_string(),
|
None => "None".to_string(),
|
||||||
};
|
};
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
@ -38,16 +39,16 @@ impl PyBuffInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
let name_str = self.name.as_ref(py).to_str()?;
|
let name_str = self.name.bind(py).to_str()?;
|
||||||
dict.set_item("name", name_str)?;
|
dict.set_item("name", name_str)?;
|
||||||
if let Some(config) = &self.config {
|
if let Some(config) = &self.config {
|
||||||
dict.set_item("config", config.as_ref(py))?;
|
dict.set_item("config", config.bind(py))?;
|
||||||
} else {
|
} else {
|
||||||
dict.set_item("config", py.None())?;
|
dict.set_item("config", py.None())?;
|
||||||
}
|
}
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ impl TryInto<MonaBuffInterface> for PyBuffInterface {
|
|||||||
|
|
||||||
fn try_into(self) -> Result<MonaBuffInterface, Self::Error> {
|
fn try_into(self) -> Result<MonaBuffInterface, Self::Error> {
|
||||||
let name: BuffName = Python::with_gil(|py| {
|
let name: BuffName = Python::with_gil(|py| {
|
||||||
let _string: &PyString = self.name.as_ref(py);
|
let _string: &Bound<'_, PyString> = self.name.bind(py);
|
||||||
depythonize(_string).map_err(|err| {
|
depythonize(_string).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _string);
|
let serialized_data = format!("{:?}", _string);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -69,7 +70,7 @@ impl TryInto<MonaBuffInterface> for PyBuffInterface {
|
|||||||
|
|
||||||
let config: BuffConfig = if let Some(value) = self.config {
|
let config: BuffConfig = if let Some(value) = self.config {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let _dict: &PyDict = value.as_ref(py);
|
let _dict: &Bound<'_, PyDict> = value.bind(py);
|
||||||
depythonize(_dict).map_err(|err| {
|
depythonize(_dict).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _dict);
|
let serialized_data = format!("{:?}", _dict);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
|
@ -52,7 +52,7 @@ impl PyCalculatorConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("character", self.character.__dict__(py)?)?;
|
dict.set_item("character", self.character.__dict__(py)?)?;
|
||||||
dict.set_item("weapon", self.weapon.__dict__(py)?)?;
|
dict.set_item("weapon", self.weapon.__dict__(py)?)?;
|
||||||
@ -60,15 +60,15 @@ impl PyCalculatorConfig {
|
|||||||
.buffs
|
.buffs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|b| b.__dict__(py))
|
.map(|b| b.__dict__(py))
|
||||||
.collect::<Result<Vec<PyObject>, PyErr>>()?;
|
.collect::<Result<Vec<Bound<PyDict>>, PyErr>>()?;
|
||||||
dict.set_item("buffs", PyList::new(py, buffs))?;
|
dict.set_item("buffs", PyList::new(py, buffs)?)?;
|
||||||
let artifacts = self
|
let artifacts = self
|
||||||
.artifacts
|
.artifacts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ar| ar.__dict__(py))
|
.map(|ar| ar.__dict__(py))
|
||||||
.collect::<Result<Vec<PyObject>, PyErr>>()?;
|
.collect::<Result<Vec<Bound<PyDict>>, PyErr>>()?;
|
||||||
dict.set_item("artifacts", PyList::new(py, artifacts))?;
|
dict.set_item("artifacts", PyList::new(py, artifacts)?)?;
|
||||||
if let Some(artifact_config) = self.artifact_config.as_ref().map(|c| c.as_ref(py)) {
|
if let Some(artifact_config) = self.artifact_config.as_ref().map(|c| c.bind(py)) {
|
||||||
dict.set_item("artifact_config", artifact_config)?;
|
dict.set_item("artifact_config", artifact_config)?;
|
||||||
} else {
|
} else {
|
||||||
dict.set_item("artifact_config", py.None())?;
|
dict.set_item("artifact_config", py.None())?;
|
||||||
@ -79,6 +79,6 @@ impl PyCalculatorConfig {
|
|||||||
} else {
|
} else {
|
||||||
dict.set_item("enemy", py.None())?;
|
dict.set_item("enemy", py.None())?;
|
||||||
}
|
}
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ pub struct PyCharacterInterface {
|
|||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyCharacterInterface {
|
impl PyCharacterInterface {
|
||||||
#[new]
|
#[new]
|
||||||
|
#[pyo3(signature = (name, level, ascend, constellation, skill1, skill2, skill3, params=None))]
|
||||||
pub fn py_new(
|
pub fn py_new(
|
||||||
name: String,
|
name: String,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -66,7 +67,7 @@ impl PyCharacterInterface {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
|
|
||||||
dict.set_item("name", &self.name)?;
|
dict.set_item("name", &self.name)?;
|
||||||
@ -83,7 +84,7 @@ impl PyCharacterInterface {
|
|||||||
dict.set_item("params", py.None())?;
|
dict.set_item("params", py.None())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ impl TryInto<MonaCharacterInterface> for PyCharacterInterface {
|
|||||||
.context("Failed to name params into mona::character::CharacterName")?;
|
.context("Failed to name params into mona::character::CharacterName")?;
|
||||||
let params: CharacterConfig = if let Some(value) = self.params {
|
let params: CharacterConfig = if let Some(value) = self.params {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let _dict: &PyDict = value.as_ref(py);
|
let _dict: &Bound<'_, PyDict> = value.bind(py);
|
||||||
depythonize(_dict).map_err(|err| {
|
depythonize(_dict).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _dict);
|
let serialized_data = format!("{:?}", _dict);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -158,13 +159,9 @@ mod tests {
|
|||||||
|
|
||||||
match &py_character_interface.params {
|
match &py_character_interface.params {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let py_dict = value.as_ref(py);
|
let py_dict = value.bind(py);
|
||||||
let hutao_dict = py_dict
|
let hutao_dict = py_dict.get_item("HuTao").unwrap().unwrap();
|
||||||
.get_item("HuTao")
|
let hutao_dict = hutao_dict.downcast::<PyDict>().unwrap();
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<PyDict>()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hutao_dict
|
hutao_dict
|
||||||
.get_item("le_50")
|
.get_item("le_50")
|
||||||
@ -211,7 +208,8 @@ mod tests {
|
|||||||
pyo3::prepare_freethreaded_python();
|
pyo3::prepare_freethreaded_python();
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let module = PyModule::import(py, "python_genshin_artifact.enka.characters")?;
|
let module = PyModule::import(py, "python_genshin_artifact.enka.characters")?;
|
||||||
let characters_map = module.getattr("characters_map")?.downcast::<PyDict>()?;
|
let characters_map = module.getattr("characters_map")?;
|
||||||
|
let characters_map = characters_map.downcast::<PyDict>()?;
|
||||||
for (_, value) in characters_map.iter() {
|
for (_, value) in characters_map.iter() {
|
||||||
let character_name_str = value.extract::<String>()?;
|
let character_name_str = value.extract::<String>()?;
|
||||||
let res = CharacterName::from_str(&character_name_str).context(format!(
|
let res = CharacterName::from_str(&character_name_str).context(format!(
|
||||||
|
@ -69,7 +69,7 @@ impl PyEnemyInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("level", self.level)?;
|
dict.set_item("level", self.level)?;
|
||||||
dict.set_item("electro_res", self.electro_res)?;
|
dict.set_item("electro_res", self.electro_res)?;
|
||||||
@ -80,7 +80,7 @@ impl PyEnemyInterface {
|
|||||||
dict.set_item("anemo_res", self.anemo_res)?;
|
dict.set_item("anemo_res", self.anemo_res)?;
|
||||||
dict.set_item("dendro_res", self.dendro_res)?;
|
dict.set_item("dendro_res", self.dendro_res)?;
|
||||||
dict.set_item("physical_res", self.physical_res)?;
|
dict.set_item("physical_res", self.physical_res)?;
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ pub struct PySkillInterface {
|
|||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PySkillInterface {
|
impl PySkillInterface {
|
||||||
#[new]
|
#[new]
|
||||||
|
#[pyo3(signature = (index, config=None))]
|
||||||
fn new(index: usize, config: Option<Py<PyDict>>) -> PyResult<Self> {
|
fn new(index: usize, config: Option<Py<PyDict>>) -> PyResult<Self> {
|
||||||
Ok(Self { index, config })
|
Ok(Self { index, config })
|
||||||
}
|
}
|
||||||
@ -29,15 +30,15 @@ impl PySkillInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("index", self.index)?;
|
dict.set_item("index", self.index)?;
|
||||||
if let Some(config) = &self.config {
|
if let Some(config) = &self.config {
|
||||||
dict.set_item("config", config.as_ref(py))?;
|
dict.set_item("config", config.bind(py))?;
|
||||||
} else {
|
} else {
|
||||||
dict.set_item("config", py.None())?;
|
dict.set_item("config", py.None())?;
|
||||||
}
|
}
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ impl TryInto<MonaSkillInterface> for PySkillInterface {
|
|||||||
fn try_into(self) -> Result<MonaSkillInterface, Self::Error> {
|
fn try_into(self) -> Result<MonaSkillInterface, Self::Error> {
|
||||||
let config: CharacterSkillConfig = if let Some(value) = self.config {
|
let config: CharacterSkillConfig = if let Some(value) = self.config {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let _dict: &PyDict = value.as_ref(py);
|
let _dict: &Bound<'_, PyDict> = value.bind(py);
|
||||||
depythonize(_dict).map_err(|err| {
|
depythonize(_dict).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _dict);
|
let serialized_data = format!("{:?}", _dict);
|
||||||
anyhow!("Failed to deserialize config into mona::character::skill_config::CharacterSkillConfig: {}. Serialized data: \n{}", err, serialized_data)
|
anyhow!("Failed to deserialize config into mona::character::skill_config::CharacterSkillConfig: {}. Serialized data: \n{}", err, serialized_data)
|
||||||
|
@ -25,6 +25,7 @@ pub struct PyWeaponInterface {
|
|||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyWeaponInterface {
|
impl PyWeaponInterface {
|
||||||
#[new]
|
#[new]
|
||||||
|
#[pyo3(signature = (name, level, ascend, refine, params=None))]
|
||||||
pub fn py_new(
|
pub fn py_new(
|
||||||
name: Py<PyString>,
|
name: Py<PyString>,
|
||||||
level: i32,
|
level: i32,
|
||||||
@ -42,9 +43,9 @@ impl PyWeaponInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
pub fn __repr__(&self, py: Python) -> PyResult<String> {
|
||||||
let name = self.name.as_ref(py).to_str()?;
|
let name = self.name.bind(py).to_str()?;
|
||||||
let params_repr = match &self.params {
|
let params_repr = match &self.params {
|
||||||
Some(params) => params.as_ref(py).repr()?.to_str()?.to_string(),
|
Some(params) => params.bind(py).repr()?.to_str()?.to_string(),
|
||||||
None => "None".to_string(),
|
None => "None".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,18 +56,18 @@ impl PyWeaponInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("name", self.name.as_ref(py))?;
|
dict.set_item("name", self.name.bind(py))?;
|
||||||
dict.set_item("level", self.level)?;
|
dict.set_item("level", self.level)?;
|
||||||
dict.set_item("ascend", self.ascend)?;
|
dict.set_item("ascend", self.ascend)?;
|
||||||
dict.set_item("refine", self.refine)?;
|
dict.set_item("refine", self.refine)?;
|
||||||
if let Some(params) = &self.params {
|
if let Some(params) = &self.params {
|
||||||
dict.set_item("params", params.as_ref(py))?;
|
dict.set_item("params", params.bind(py))?;
|
||||||
} else {
|
} else {
|
||||||
dict.set_item("params", py.None())?;
|
dict.set_item("params", py.None())?;
|
||||||
}
|
}
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ impl TryInto<MonaWeaponInterface> for PyWeaponInterface {
|
|||||||
|
|
||||||
fn try_into(self) -> Result<MonaWeaponInterface, Self::Error> {
|
fn try_into(self) -> Result<MonaWeaponInterface, Self::Error> {
|
||||||
let name: WeaponName = Python::with_gil(|py| {
|
let name: WeaponName = Python::with_gil(|py| {
|
||||||
let _string: &PyString = self.name.as_ref(py);
|
let _string: &Bound<'_, PyString> = self.name.bind(py);
|
||||||
depythonize(_string).map_err(|err| {
|
depythonize(_string).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _string);
|
let serialized_data = format!("{:?}", _string);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -88,7 +89,7 @@ impl TryInto<MonaWeaponInterface> for PyWeaponInterface {
|
|||||||
|
|
||||||
let params: WeaponConfig = if let Some(value) = self.params {
|
let params: WeaponConfig = if let Some(value) = self.params {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let _dict: &PyDict = value.as_ref(py);
|
let _dict: &Bound<'_, PyDict> = value.bind(py);
|
||||||
depythonize(_dict).map_err(|err| {
|
depythonize(_dict).map_err(|err| {
|
||||||
let serialized_data = format!("{:?}", _dict);
|
let serialized_data = format!("{:?}", _dict);
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -139,23 +140,16 @@ mod tests {
|
|||||||
params: Some(Py::from(params_dict)),
|
params: Some(Py::from(params_dict)),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(py_weapon_interface.name.bind(py).to_string(), "StaffOfHoma");
|
||||||
py_weapon_interface.name.as_ref(py).to_string(),
|
|
||||||
"StaffOfHoma"
|
|
||||||
);
|
|
||||||
assert_eq!(py_weapon_interface.level, 90);
|
assert_eq!(py_weapon_interface.level, 90);
|
||||||
assert!(py_weapon_interface.ascend);
|
assert!(py_weapon_interface.ascend);
|
||||||
assert_eq!(py_weapon_interface.refine, 5);
|
assert_eq!(py_weapon_interface.refine, 5);
|
||||||
|
|
||||||
match &py_weapon_interface.params {
|
match &py_weapon_interface.params {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
let py_dict = value.as_ref(py);
|
let py_dict = value.bind(py);
|
||||||
let params_dict = py_dict
|
let params_dict = py_dict.get_item("StaffOfHoma").unwrap().unwrap();
|
||||||
.get_item("StaffOfHoma")
|
let params_dict = params_dict.downcast::<PyDict>().unwrap();
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<PyDict>()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
params_dict
|
params_dict
|
||||||
.get_item("be50_rate")
|
.get_item("be50_rate")
|
||||||
@ -223,7 +217,8 @@ mod tests {
|
|||||||
pyo3::prepare_freethreaded_python();
|
pyo3::prepare_freethreaded_python();
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let module = PyModule::import(py, "python_genshin_artifact.enka.weapon")?;
|
let module = PyModule::import(py, "python_genshin_artifact.enka.weapon")?;
|
||||||
let weapon_name_map = module.getattr("weapon_name_map")?.downcast::<PyDict>()?;
|
let weapon_name_map = module.getattr("weapon_name_map")?;
|
||||||
|
let weapon_name_map = weapon_name_map.downcast::<PyDict>()?;
|
||||||
for (_, value) in weapon_name_map.iter() {
|
for (_, value) in weapon_name_map.iter() {
|
||||||
let weapon_name_str = value.extract::<String>()?;
|
let weapon_name_str = value.extract::<String>()?;
|
||||||
let res: Result<WeaponName, anyhow::Error> = depythonize(&value)
|
let res: Result<WeaponName, anyhow::Error> = depythonize(&value)
|
||||||
|
@ -73,11 +73,12 @@ pub struct PyDamageAnalysis {
|
|||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PyDamageAnalysis {
|
impl PyDamageAnalysis {
|
||||||
#[getter]
|
#[getter]
|
||||||
fn __dict__(&self, py: Python) -> PyResult<PyObject> { // skipcq: RS-R1000
|
fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
|
// skipcq: RS-R1000
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
|
|
||||||
fn insert_hashmap(
|
fn insert_hashmap(
|
||||||
dict: &PyDict,
|
dict: &Bound<PyDict>,
|
||||||
py: Python,
|
py: Python,
|
||||||
key: &str,
|
key: &str,
|
||||||
hashmap: &HashMap<String, f64>,
|
hashmap: &HashMap<String, f64>,
|
||||||
@ -90,27 +91,27 @@ impl PyDamageAnalysis {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
insert_hashmap(dict, py, "atk", &self.atk)?;
|
insert_hashmap(&dict, py, "atk", &self.atk)?;
|
||||||
insert_hashmap(dict, py, "atk_ratio", &self.atk_ratio)?;
|
insert_hashmap(&dict, py, "atk_ratio", &self.atk_ratio)?;
|
||||||
insert_hashmap(dict, py, "hp", &self.hp)?;
|
insert_hashmap(&dict, py, "hp", &self.hp)?;
|
||||||
insert_hashmap(dict, py, "hp_ratio", &self.hp_ratio)?;
|
insert_hashmap(&dict, py, "hp_ratio", &self.hp_ratio)?;
|
||||||
insert_hashmap(dict, py, "defense", &self.def)?;
|
insert_hashmap(&dict, py, "defense", &self.def)?;
|
||||||
insert_hashmap(dict, py, "def_ratio", &self.def_ratio)?;
|
insert_hashmap(&dict, py, "def_ratio", &self.def_ratio)?;
|
||||||
insert_hashmap(dict, py, "em", &self.em)?;
|
insert_hashmap(&dict, py, "em", &self.em)?;
|
||||||
insert_hashmap(dict, py, "em_ratio", &self.em_ratio)?;
|
insert_hashmap(&dict, py, "em_ratio", &self.em_ratio)?;
|
||||||
insert_hashmap(dict, py, "extra_damage", &self.extra_damage)?;
|
insert_hashmap(&dict, py, "extra_damage", &self.extra_damage)?;
|
||||||
insert_hashmap(dict, py, "bonus", &self.bonus)?;
|
insert_hashmap(&dict, py, "bonus", &self.bonus)?;
|
||||||
insert_hashmap(dict, py, "critical", &self.critical)?;
|
insert_hashmap(&dict, py, "critical", &self.critical)?;
|
||||||
insert_hashmap(dict, py, "critical_damage", &self.critical_damage)?;
|
insert_hashmap(&dict, py, "critical_damage", &self.critical_damage)?;
|
||||||
insert_hashmap(dict, py, "melt_enhance", &self.melt_enhance)?;
|
insert_hashmap(&dict, py, "melt_enhance", &self.melt_enhance)?;
|
||||||
insert_hashmap(dict, py, "vaporize_enhance", &self.vaporize_enhance)?;
|
insert_hashmap(&dict, py, "vaporize_enhance", &self.vaporize_enhance)?;
|
||||||
insert_hashmap(dict, py, "healing_bonus", &self.healing_bonus)?;
|
insert_hashmap(&dict, py, "healing_bonus", &self.healing_bonus)?;
|
||||||
insert_hashmap(dict, py, "shield_strength", &self.shield_strength)?;
|
insert_hashmap(&dict, py, "shield_strength", &self.shield_strength)?;
|
||||||
insert_hashmap(dict, py, "spread_compose", &self.spread_compose)?;
|
insert_hashmap(&dict, py, "spread_compose", &self.spread_compose)?;
|
||||||
insert_hashmap(dict, py, "aggravate_compose", &self.aggravate_compose)?;
|
insert_hashmap(&dict, py, "aggravate_compose", &self.aggravate_compose)?;
|
||||||
insert_hashmap(dict, py, "def_minus", &self.def_minus)?;
|
insert_hashmap(&dict, py, "def_minus", &self.def_minus)?;
|
||||||
insert_hashmap(dict, py, "def_penetration", &self.def_penetration)?;
|
insert_hashmap(&dict, py, "def_penetration", &self.def_penetration)?;
|
||||||
insert_hashmap(dict, py, "res_minus", &self.res_minus)?;
|
insert_hashmap(&dict, py, "res_minus", &self.res_minus)?;
|
||||||
|
|
||||||
dict.set_item("element", &self.element)?;
|
dict.set_item("element", &self.element)?;
|
||||||
dict.set_item("is_heal", self.is_heal)?;
|
dict.set_item("is_heal", self.is_heal)?;
|
||||||
@ -143,7 +144,7 @@ impl PyDamageAnalysis {
|
|||||||
dict.set_item("aggravate", py.None())?;
|
dict.set_item("aggravate", py.None())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ use mona::damage::damage_result::DamageResult as MonaDamageResult;
|
|||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::{PyBytes, PyDict};
|
use pyo3::types::{PyBytes, PyDict};
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use bincode::{deserialize, serialize};
|
||||||
use bincode::{serialize, deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[pyclass(module = "python_genshin_artifact", name = "DamageResult")]
|
#[pyclass(module = "python_genshin_artifact", name = "DamageResult")]
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
@ -47,22 +47,22 @@ impl PyDamageResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("critical", self.critical)?;
|
dict.set_item("critical", self.critical)?;
|
||||||
dict.set_item("non_critical", self.non_critical)?;
|
dict.set_item("non_critical", self.non_critical)?;
|
||||||
dict.set_item("expectation", self.expectation)?;
|
dict.set_item("expectation", self.expectation)?;
|
||||||
dict.set_item("is_heal", self.is_heal)?;
|
dict.set_item("is_heal", self.is_heal)?;
|
||||||
dict.set_item("is_shield", self.is_shield)?;
|
dict.set_item("is_shield", self.is_shield)?;
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __setstate__(&mut self, state: &PyBytes) -> PyResult<()> {
|
pub fn __setstate__(&mut self, state: Bound<'_, PyBytes>) -> PyResult<()> {
|
||||||
*self = deserialize(state.as_bytes()).unwrap();
|
*self = deserialize(state.as_bytes()).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<&'py PyBytes> {
|
pub fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
|
||||||
Ok(PyBytes::new(py, &serialize(&self).unwrap()))
|
Ok(PyBytes::new(py, &serialize(&self).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ impl PyTransformativeDamage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
pub fn __dict__(&self, py: Python) -> PyResult<PyObject> {
|
pub fn __dict__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
|
||||||
let dict = PyDict::new(py);
|
let dict = PyDict::new(py);
|
||||||
dict.set_item("swirl_cryo", self.swirl_cryo)?;
|
dict.set_item("swirl_cryo", self.swirl_cryo)?;
|
||||||
dict.set_item("swirl_hydro", self.swirl_hydro)?;
|
dict.set_item("swirl_hydro", self.swirl_hydro)?;
|
||||||
@ -84,7 +84,7 @@ impl PyTransformativeDamage {
|
|||||||
dict.set_item("burgeon", self.burgeon)?;
|
dict.set_item("burgeon", self.burgeon)?;
|
||||||
dict.set_item("burning", self.burning)?;
|
dict.set_item("burning", self.burning)?;
|
||||||
dict.set_item("crystallize", self.crystallize)?;
|
dict.set_item("crystallize", self.crystallize)?;
|
||||||
Ok(dict.into())
|
Ok(dict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use crate::applications::output::transformative_damage::PyTransformativeDamage;
|
|||||||
import_exception!(json, JSONDecodeError);
|
import_exception!(json, JSONDecodeError);
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn _python_genshin_artifact(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn _python_genshin_artifact(py: Python<'_>, m: &Bound<PyModule>) -> PyResult<()> {
|
||||||
m.add("JSONDecodeError", py.get_type::<JSONDecodeError>())?;
|
m.add("JSONDecodeError", py.get_type::<JSONDecodeError>())?;
|
||||||
m.add_function(wrap_pyfunction!(get_damage_analysis, m)?)?;
|
m.add_function(wrap_pyfunction!(get_damage_analysis, m)?)?;
|
||||||
m.add_function(wrap_pyfunction!(get_transformative_damage, m)?)?;
|
m.add_function(wrap_pyfunction!(get_transformative_damage, m)?)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user