solax-py-library 1.0.0.14__py3-none-any.whl → 1.0.0.16__py3-none-any.whl

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 (29) hide show
  1. solax_py_library/__init__.py +1 -1
  2. solax_py_library/snap_shot/__init__.py +4 -4
  3. solax_py_library/snap_shot/address.py +299 -67
  4. solax_py_library/snap_shot/base_modbus.py +14 -14
  5. solax_py_library/snap_shot/core.py +249 -219
  6. solax_py_library/snap_shot/exceptions.py +6 -4
  7. solax_py_library/snap_shot/parser.py +226 -224
  8. solax_py_library/snap_shot/untils.py +20 -17
  9. solax_py_library/upload/__init__.py +3 -3
  10. solax_py_library/upload/api/__init__.py +3 -3
  11. solax_py_library/upload/api/service.py +24 -24
  12. solax_py_library/upload/core/__init__.py +3 -3
  13. solax_py_library/upload/core/data_adapter/__init__.py +5 -5
  14. solax_py_library/upload/core/data_adapter/base.py +9 -9
  15. solax_py_library/upload/core/data_adapter/csv.py +26 -26
  16. solax_py_library/upload/core/upload_service/__init__.py +15 -15
  17. solax_py_library/upload/core/upload_service/base.py +43 -43
  18. solax_py_library/upload/core/upload_service/ftp.py +97 -86
  19. solax_py_library/upload/errors/__init__.py +10 -10
  20. solax_py_library/upload/errors/base.py +10 -10
  21. solax_py_library/upload/errors/upload_error.py +21 -21
  22. solax_py_library/upload/test/test_ftp.py +81 -40
  23. solax_py_library/upload/types/__init__.py +11 -11
  24. solax_py_library/upload/types/client.py +19 -19
  25. solax_py_library/upload/types/ftp.py +37 -37
  26. {solax_py_library-1.0.0.14.dist-info → solax_py_library-1.0.0.16.dist-info}/METADATA +4 -4
  27. solax_py_library-1.0.0.16.dist-info/RECORD +29 -0
  28. {solax_py_library-1.0.0.14.dist-info → solax_py_library-1.0.0.16.dist-info}/WHEEL +1 -1
  29. solax_py_library-1.0.0.14.dist-info/RECORD +0 -29
@@ -1,26 +1,26 @@
1
- import csv
2
- import tempfile
3
- from typing import Any, Union, List, Dict
4
-
5
- from solax_py_library.upload.core.data_adapter.base import BaseDataAdapter
6
-
7
-
8
- class CSVDataAdapter(BaseDataAdapter):
9
- @classmethod
10
- def parse_data(cls, data: Union[List[List[Any]], List[Dict[str, Any]]]):
11
- with tempfile.NamedTemporaryFile(
12
- delete=False, mode="w", newline="", encoding="utf-8-sig"
13
- ) as temp_file:
14
- if isinstance(data[0], list):
15
- writer = csv.writer(temp_file)
16
- writer.writerows(data)
17
- else:
18
- headers = list(data[0].keys())
19
- writer = csv.DictWriter(temp_file, fieldnames=headers)
20
- writer.writeheader()
21
- writer.writerows(data)
22
-
23
- temp_file_path = temp_file.name
24
- temp_file.seek(0)
25
-
26
- return temp_file_path
1
+ import csv
2
+ import tempfile
3
+ from typing import Any, Union, List, Dict
4
+
5
+ from solax_py_library.upload.core.data_adapter.base import BaseDataAdapter
6
+
7
+
8
+ class CSVDataAdapter(BaseDataAdapter):
9
+ @classmethod
10
+ def parse_data(cls, data: Union[List[List[Any]], List[Dict[str, Any]]]):
11
+ with tempfile.NamedTemporaryFile(
12
+ delete=False, mode="w", newline="", encoding="utf-8-sig"
13
+ ) as temp_file:
14
+ if isinstance(data[0], list):
15
+ writer = csv.writer(temp_file)
16
+ writer.writerows(data)
17
+ else:
18
+ headers = list(data[0].keys())
19
+ writer = csv.DictWriter(temp_file, fieldnames=headers)
20
+ writer.writeheader()
21
+ writer.writerows(data)
22
+
23
+ temp_file_path = temp_file.name
24
+ temp_file.seek(0)
25
+
26
+ return temp_file_path
@@ -1,15 +1,15 @@
1
- from .base import BaseUploadService
2
- from .ftp import FTPUploadService
3
-
4
-
5
- upload_service_map = {}
6
-
7
-
8
- def _register(upload_obj):
9
- upload_service_map[upload_obj.upload_type] = upload_obj
10
-
11
-
12
- _register(FTPUploadService)
13
-
14
-
15
- __all__ = ["BaseUploadService", "FTPUploadService"]
1
+ from .base import BaseUploadService
2
+ from .ftp import FTPUploadService
3
+
4
+
5
+ upload_service_map = {}
6
+
7
+
8
+ def _register(upload_obj):
9
+ upload_service_map[upload_obj.upload_type] = upload_obj
10
+
11
+
12
+ _register(FTPUploadService)
13
+
14
+
15
+ __all__ = ["BaseUploadService", "FTPUploadService"]
@@ -1,43 +1,43 @@
1
- from abc import ABCMeta, abstractmethod
2
-
3
- from solax_py_library.upload.types.client import UploadData
4
-
5
-
6
- class BaseUploadService(metaclass=ABCMeta):
7
- upload_type = None
8
-
9
- def __init__(self, **kwargs) -> None:
10
- self._client = None
11
- self._is_connect = False
12
- self.timeout = 5
13
-
14
- @abstractmethod
15
- def connect(self):
16
- ...
17
-
18
- async def upload(self, data: UploadData):
19
- upload_data = self._parse(data.build_data())
20
- return self._upload(upload_data)
21
-
22
- @abstractmethod
23
- def close(self):
24
- ...
25
-
26
- @property
27
- def is_connect(self):
28
- return self._is_connect
29
-
30
- def __enter__(self):
31
- self.connect()
32
- return self
33
-
34
- def __exit__(self, exc_type, exc_value, traceback):
35
- self.close()
36
-
37
- @abstractmethod
38
- def _upload(self, data):
39
- ...
40
-
41
- @abstractmethod
42
- def _parse(self, upload_data: UploadData):
43
- ...
1
+ from abc import ABCMeta, abstractmethod
2
+
3
+ from solax_py_library.upload.types.client import UploadData
4
+
5
+
6
+ class BaseUploadService(metaclass=ABCMeta):
7
+ upload_type = None
8
+
9
+ def __init__(self, **kwargs) -> None:
10
+ self._client = None
11
+ self._is_connect = False
12
+ self.timeout = 5
13
+
14
+ @abstractmethod
15
+ def connect(self):
16
+ ...
17
+
18
+ async def upload(self, data: UploadData):
19
+ upload_data = self._parse(data.build_data())
20
+ return self._upload(upload_data)
21
+
22
+ @abstractmethod
23
+ def close(self):
24
+ ...
25
+
26
+ @property
27
+ def is_connect(self):
28
+ return self._is_connect
29
+
30
+ def __enter__(self):
31
+ self.connect()
32
+ return self
33
+
34
+ def __exit__(self, exc_type, exc_value, traceback):
35
+ self.close()
36
+
37
+ @abstractmethod
38
+ def _upload(self, data):
39
+ ...
40
+
41
+ @abstractmethod
42
+ def _parse(self, upload_data: UploadData):
43
+ ...
@@ -1,86 +1,97 @@
1
- import ftplib
2
- import os
3
-
4
- from .base import BaseUploadService
5
- from solax_py_library.upload.types.client import UploadType
6
- from solax_py_library.upload.core.data_adapter import CSVDataAdapter
7
- from solax_py_library.upload.types.ftp import (
8
- FTPServiceConfig,
9
- FTPFileType,
10
- FTPData,
11
- FTPParsedData,
12
- )
13
- from solax_py_library.upload.errors.upload_error import (
14
- SendDataError,
15
- ConnectError,
16
- ConfigurationError,
17
- )
18
-
19
-
20
- class FTPUploadService(BaseUploadService):
21
- upload_type = UploadType.FTP
22
-
23
- def __init__(self, **kwargs):
24
- super().__init__(**kwargs)
25
- config = self._init_config(**kwargs)
26
- self.host = config.host
27
- self.port = config.port
28
- self.user = config.user
29
- self.password = config.password
30
- self.remote_path = config.remote_path
31
-
32
- def _init_config(self, **kwargs):
33
- try:
34
- return FTPServiceConfig(**kwargs)
35
- except Exception as e:
36
- print(e)
37
- raise ConfigurationError
38
-
39
- def connect(self):
40
- if self._client is not None:
41
- self.close()
42
- try:
43
- self._client = ftplib.FTP(self.host, timeout=self.timeout)
44
- self._client.connect(self.host, self.port, timeout=self.timeout)
45
- self._client.login(self.user, self.password)
46
- print(f"Connected to {self.host}")
47
- self._is_connect = True
48
- except Exception as e:
49
- print(e)
50
- raise ConnectError
51
-
52
- def close(self):
53
- if self._client:
54
- self._client.quit()
55
- self._client = None
56
- self._is_connect = False
57
- print("Connection closed.")
58
-
59
- def _parse(self, upload_data: FTPData) -> FTPParsedData:
60
- if upload_data.file_type == FTPFileType.CSV:
61
- parsed_data = CSVDataAdapter.parse_data(upload_data.data)
62
- else:
63
- raise NotImplementedError
64
- return FTPParsedData(
65
- file_name=upload_data.file_name + FTPFileType.get_file_suffix(upload_data.file_type),
66
- file_path=parsed_data,
67
- )
68
-
69
- def _upload(self, data: FTPParsedData):
70
- try:
71
- if not self._is_connect:
72
- raise ConnectError(message="not connect yet")
73
- with open(data.file_path, "rb") as f:
74
- self._client.storbinary(
75
- f"STOR {self._build_remote_file(data.file_name)}", f
76
- )
77
- print(f"Successfully uploaded to {data.file_name}")
78
- except Exception as e:
79
- print(e)
80
- raise SendDataError
81
- finally:
82
- if os.path.exists(data.file_path):
83
- os.remove(data.file_path)
84
-
85
- def _build_remote_file(self, file_name):
86
- return os.path.join(self.remote_path, file_name)
1
+ import ftplib
2
+ import os
3
+
4
+ from .base import BaseUploadService
5
+ from solax_py_library.upload.types.client import UploadType
6
+ from solax_py_library.upload.core.data_adapter import CSVDataAdapter
7
+ from solax_py_library.upload.types.ftp import (
8
+ FTPServiceConfig,
9
+ FTPFileType,
10
+ FTPData,
11
+ FTPParsedData,
12
+ )
13
+ from solax_py_library.upload.errors.upload_error import (
14
+ SendDataError,
15
+ ConnectError,
16
+ LoginError,
17
+ ConfigurationError,
18
+ )
19
+
20
+
21
+ class FTPUploadService(BaseUploadService):
22
+ upload_type = UploadType.FTP
23
+
24
+ def __init__(self, **kwargs):
25
+ super().__init__(**kwargs)
26
+ config = self._init_config(**kwargs)
27
+ self.host = config.host
28
+ self.port = config.port
29
+ self.user = config.user
30
+ self.password = config.password
31
+ self.remote_path = config.remote_path
32
+
33
+ def _init_config(self, **kwargs):
34
+ try:
35
+ return FTPServiceConfig(**kwargs)
36
+ except Exception as e:
37
+ print(e)
38
+ raise ConfigurationError
39
+
40
+ def connect(self):
41
+ if self._client is not None:
42
+ self.close()
43
+ self._connect()
44
+ self._login()
45
+ self._is_connect = True
46
+
47
+ def _connect(self):
48
+ try:
49
+ self._client = ftplib.FTP(self.host, timeout=self.timeout)
50
+ self._client.connect(self.host, self.port, timeout=self.timeout)
51
+ except Exception as e:
52
+ print(e)
53
+ raise ConnectError
54
+
55
+ def _login(self):
56
+ try:
57
+ self._client.login(self.user, self.password)
58
+ except Exception as e:
59
+ print(e)
60
+ raise LoginError
61
+
62
+ def close(self):
63
+ if self._client:
64
+ self._client.quit()
65
+ self._client = None
66
+ self._is_connect = False
67
+ print("Connection closed.")
68
+
69
+ def _parse(self, upload_data: FTPData) -> FTPParsedData:
70
+ if upload_data.file_type == FTPFileType.CSV:
71
+ parsed_data = CSVDataAdapter.parse_data(upload_data.data)
72
+ else:
73
+ raise NotImplementedError
74
+ return FTPParsedData(
75
+ file_name=upload_data.file_name
76
+ + FTPFileType.get_file_suffix(upload_data.file_type),
77
+ file_path=parsed_data,
78
+ )
79
+
80
+ def _upload(self, data: FTPParsedData):
81
+ try:
82
+ if not self._is_connect:
83
+ raise ConnectError(message="not connect yet")
84
+ with open(data.file_path, "rb") as f:
85
+ self._client.storbinary(
86
+ f"STOR {self._build_remote_file(data.file_name)}", f
87
+ )
88
+ print(f"Successfully uploaded to {data.file_name}")
89
+ except Exception as e:
90
+ print(e)
91
+ raise SendDataError
92
+ finally:
93
+ if os.path.exists(data.file_path):
94
+ os.remove(data.file_path)
95
+
96
+ def _build_remote_file(self, file_name):
97
+ return os.path.join(self.remote_path, file_name)
@@ -1,10 +1,10 @@
1
- from .base import UploadBaseError
2
- from .upload_error import ConfigurationError, ConnectError, LoginError, SendDataError
3
-
4
- __all__ = [
5
- "UploadBaseError",
6
- "ConnectError",
7
- "LoginError",
8
- "SendDataError",
9
- "ConfigurationError",
10
- ]
1
+ from .base import UploadBaseError
2
+ from .upload_error import ConfigurationError, ConnectError, LoginError, SendDataError
3
+
4
+ __all__ = [
5
+ "UploadBaseError",
6
+ "ConnectError",
7
+ "LoginError",
8
+ "SendDataError",
9
+ "ConfigurationError",
10
+ ]
@@ -1,10 +1,10 @@
1
- class UploadBaseError(Exception):
2
- code = 0x1000
3
- message = "upload error"
4
-
5
- def __init__(self, *args, message=None):
6
- super().__init__(*args)
7
- self.message = message or self.message
8
-
9
- def __str__(self):
10
- return self.message
1
+ class UploadBaseError(Exception):
2
+ code = 0x1000
3
+ message = "upload error"
4
+
5
+ def __init__(self, *args, message=None):
6
+ super().__init__(*args)
7
+ self.message = message or self.message
8
+
9
+ def __str__(self):
10
+ return self.message
@@ -1,21 +1,21 @@
1
- from .base import UploadBaseError
2
-
3
-
4
- class ConnectError(UploadBaseError):
5
- code = 0x1001
6
- message = "connect error"
7
-
8
-
9
- class LoginError(UploadBaseError):
10
- code = 0x1002
11
- message = "authentication error"
12
-
13
-
14
- class SendDataError(UploadBaseError):
15
- code = 0x1003
16
- message = "send data error"
17
-
18
-
19
- class ConfigurationError(UploadBaseError):
20
- code = 0x1004
21
- message = "server configuration error"
1
+ from .base import UploadBaseError
2
+
3
+
4
+ class ConnectError(UploadBaseError):
5
+ code = 0x1001
6
+ message = "connect error"
7
+
8
+
9
+ class LoginError(UploadBaseError):
10
+ code = 0x1002
11
+ message = "authentication error"
12
+
13
+
14
+ class SendDataError(UploadBaseError):
15
+ code = 0x1003
16
+ message = "send data error"
17
+
18
+
19
+ class ConfigurationError(UploadBaseError):
20
+ code = 0x1004
21
+ message = "server configuration error"
@@ -1,40 +1,81 @@
1
- import asyncio
2
- import unittest
3
-
4
- from solax_py_library.upload.api.service import upload
5
- from solax_py_library.upload.types.client import UploadType, UploadData
6
- from solax_py_library.upload.types.ftp import FTPFileType
7
-
8
-
9
- class FTPTest(unittest.TestCase):
10
- def test_ftp_upload(self):
11
- ftp_config = {
12
- "host": "10.1.31.181", # 测试host
13
- "port": 21,
14
- "user": "solax",
15
- "password": "123456",
16
- "remote_path": "/xixi",
17
- }
18
- asyncio.run(
19
- upload(
20
- upload_type=UploadType.FTP,
21
- configuration=ftp_config,
22
- upload_data=UploadData(
23
- upload_type=UploadType.FTP,
24
- data=dict(
25
- file_type=FTPFileType.CSV,
26
- file_name="new_file",
27
- data=[
28
- {
29
- "EMS1000序列号": "XMG11A011L",
30
- "EMS1000本地时间": "2025-02-11 15:39:10",
31
- "EMS1000版本号": "V007.11.1",
32
- "电站所在国家和地区": None,
33
- "电站所在当前时区": None,
34
- "电站系统类型": None,
35
- }
36
- ],
37
- ),
38
- ),
39
- )
40
- )
1
+ import asyncio
2
+ import unittest
3
+
4
+ from solax_py_library.upload.api.service import upload
5
+ from solax_py_library.upload.core.upload_service import FTPUploadService
6
+ from solax_py_library.upload.errors import ConnectError, LoginError
7
+ from solax_py_library.upload.types.client import UploadType, UploadData
8
+ from solax_py_library.upload.types.ftp import FTPFileType
9
+
10
+
11
+ class FTPTest(unittest.TestCase):
12
+ def test_connect(self):
13
+ ftp_config = {
14
+ "host": "10.1.31.181", # 测试host
15
+ "port": 21,
16
+ "user": "solax",
17
+ "password": "123456",
18
+ "remote_path": "/xixi",
19
+ }
20
+ ftp = FTPUploadService(**ftp_config)
21
+ ftp.connect()
22
+
23
+ def test_connect_error_1(self):
24
+ ftp_config = {
25
+ "host": "10.1.31.182", # 测试host
26
+ "port": 21,
27
+ "user": "solax",
28
+ "password": "123456",
29
+ "remote_path": "/xixi",
30
+ }
31
+ ftp = FTPUploadService(**ftp_config)
32
+ try:
33
+ ftp.connect()
34
+ except ConnectError:
35
+ ...
36
+
37
+ def test_connect_error_2(self):
38
+ ftp_config = {
39
+ "host": "10.1.31.181", # 测试host
40
+ "port": 21,
41
+ "user": "solax123",
42
+ "password": "123456",
43
+ "remote_path": "/xixi",
44
+ }
45
+ ftp = FTPUploadService(**ftp_config)
46
+ try:
47
+ ftp.connect()
48
+ except LoginError:
49
+ ...
50
+
51
+ def test_ftp_upload(self):
52
+ ftp_config = {
53
+ "host": "10.1.31.181", # 测试host
54
+ "port": 21,
55
+ "user": "solax",
56
+ "password": "123456",
57
+ "remote_path": "/xixi",
58
+ }
59
+ asyncio.run(
60
+ upload(
61
+ upload_type=UploadType.FTP,
62
+ configuration=ftp_config,
63
+ upload_data=UploadData(
64
+ upload_type=UploadType.FTP,
65
+ data=dict(
66
+ file_type=FTPFileType.CSV,
67
+ file_name="new_file",
68
+ data=[
69
+ {
70
+ "EMS1000序列号": "XMG11A011L",
71
+ "EMS1000本地时间": "2025-02-11 15:39:10",
72
+ "EMS1000版本号": "V007.11.1",
73
+ "电站所在国家和地区": None,
74
+ "电站所在当前时区": None,
75
+ "电站系统类型": None,
76
+ }
77
+ ],
78
+ ),
79
+ ),
80
+ )
81
+ )
@@ -1,11 +1,11 @@
1
- from .client import UploadType, UploadData
2
- from .ftp import FTPData, FTPParsedData, FTPFileType, FTPServiceConfig
3
-
4
- __all__ = [
5
- "FTPData",
6
- "FTPParsedData",
7
- "FTPServiceConfig",
8
- "UploadType",
9
- "UploadData",
10
- "FTPFileType",
11
- ]
1
+ from .client import UploadType, UploadData
2
+ from .ftp import FTPData, FTPParsedData, FTPFileType, FTPServiceConfig
3
+
4
+ __all__ = [
5
+ "FTPData",
6
+ "FTPParsedData",
7
+ "FTPServiceConfig",
8
+ "UploadType",
9
+ "UploadData",
10
+ "FTPFileType",
11
+ ]
@@ -1,19 +1,19 @@
1
- from enum import IntEnum
2
- from pydantic import BaseModel
3
- from typing import Optional, Union
4
-
5
- from solax_py_library.upload.types.ftp import FTPData
6
-
7
-
8
- class UploadType(IntEnum):
9
- FTP = 1
10
-
11
-
12
- class UploadData(BaseModel):
13
- data: Optional[Union[dict, FTPData]]
14
- upload_type: UploadType
15
-
16
- def build_data(self):
17
- dict_obj_data = self.data if isinstance(self.data, dict) else self.data.dict()
18
- if self.upload_type == UploadType.FTP:
19
- return FTPData(**dict_obj_data)
1
+ from enum import IntEnum
2
+ from pydantic import BaseModel
3
+ from typing import Optional, Union
4
+
5
+ from solax_py_library.upload.types.ftp import FTPData
6
+
7
+
8
+ class UploadType(IntEnum):
9
+ FTP = 1
10
+
11
+
12
+ class UploadData(BaseModel):
13
+ data: Optional[Union[dict, FTPData]]
14
+ upload_type: UploadType
15
+
16
+ def build_data(self):
17
+ dict_obj_data = self.data if isinstance(self.data, dict) else self.data.dict()
18
+ if self.upload_type == UploadType.FTP:
19
+ return FTPData(**dict_obj_data)