diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..f6f35d7 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,40 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..bdaab28 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,39 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/README.md b/README.md index 335e130..7487292 100644 --- a/README.md +++ b/README.md @@ -99,17 +99,6 @@ For more examples, please see the [SDK documentation.](https://docs.filswan.com/ This SDK has the following functionalities: -### For Onchain Storage - ---- - -- **POST** Upload file to Filswan IPFS gateway -- **GET** List of files uploaded -- **GET** Files by cid -- **GET** Status from filecoin -- **CONTRACT** Make payment to swan filecoin storage gateway -- **CONTRACT** Mint asset as NFT - ### For Buckets Storage --- diff --git a/requirements.txt b/requirements.txt index d85dd07..e393c25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -web3==5.31.1 +web3==6.15.1 requests==2.28.1 requests_toolbelt==0.10.1 tqdm==4.64.1 \ No newline at end of file diff --git a/sample/single_organization_design/README.md b/sample/single_organization_design/README.md new file mode 100644 index 0000000..6cece54 --- /dev/null +++ b/sample/single_organization_design/README.md @@ -0,0 +1,14 @@ +Source code for [Single Organization Design](https://docs.filswan.com/multichain.storage/best-practice/use-mcs-as-platform-storage-solution/single-organization-design) + +### To Install +``` +pip install python-mcs-sdk +``` +### Setup Credentials + +api_key/access_token can be found in https://www.multichain.storage/#/api_key, make sure save your APIKey and Access Token after you have generated it, you will not find it again after you created it + +### Run the script +``` +python main.py +``` diff --git a/sample/single_organization_design/data/README.md b/sample/single_organization_design/data/README.md new file mode 100644 index 0000000..905df84 --- /dev/null +++ b/sample/single_organization_design/data/README.md @@ -0,0 +1 @@ +Folder for data diff --git a/sample/single_organization_design/data/apple.jpeg b/sample/single_organization_design/data/apple.jpeg new file mode 100644 index 0000000..f4a1340 Binary files /dev/null and b/sample/single_organization_design/data/apple.jpeg differ diff --git a/sample/single_organization_design/main.py b/sample/single_organization_design/main.py new file mode 100644 index 0000000..a53c2fb --- /dev/null +++ b/sample/single_organization_design/main.py @@ -0,0 +1,33 @@ +import os + +from mcs import APIClient, BucketAPI + + +def upload_replace_file(file_path, bucket_name, dest_file_path): + """ + Upload a file by file path, bucket name and the target path + :param file_path: the source file path + :param bucket_name: the bucket name user want to upload + :param dest_file_path: the destination of the file you want to store exclude the bucket name + :return: File Object + """ + mcs_api = APIClient(api_key, access_token,network) + bucket_client = BucketAPI(mcs_api) + # check if file exist + file_data = bucket_client.get_file(bucket_name, dest_file_path) + if file_data: + print("File exist,replace file: %s" % file_path) + bucket_client.delete_file(bucket_name, dest_file_path) + file_data = bucket_client.upload_file(bucket_name, dest_file_path, file_path) + return file_data + + +if __name__ == '__main__': + api_key = "XXXX" + access_token = "xxxxxxx" + network = "polygon.mainnet" + file_path = 'data/apple.jpeg' + # file_path is the path relative to the current file + # object_name is your target path + mcs_file = upload_replace_file(file_path, "swan", + os.path.join("0x165CD37b4C644C2921454429E7F9358d18A45e14", "apple.jpeg")) diff --git a/setup.py b/setup.py index 44dddf4..9efaf2c 100644 --- a/setup.py +++ b/setup.py @@ -8,11 +8,11 @@ version="0.3.2", author="daniel8088", author_email="danilew8088@gmail.com", - install_requires=["web3==5.31.1", "requests==2.28.1", "requests_toolbelt==0.10.1", "tqdm==4.64.1"], + install_requires=["web3==6.15.1", "requests==2.28.1", "requests_toolbelt==0.10.1", "tqdm==4.64.1","eth_typing==4.1.0"], packages=["swan_mcs", "swan_mcs.api", "swan_mcs.contract", "swan_mcs.contract.abi", "swan_mcs.common", "swan_mcs.object"], license="MIT", include_package_data=True, description="A python software development kit for the Multi-Chain Storage", long_description=long_description, long_description_content_type='text/markdown', - ) + ) \ No newline at end of file diff --git a/swan_mcs/api/bucket_api.py b/swan_mcs/api/bucket_api.py index 431491f..a8fa95d 100644 --- a/swan_mcs/api/bucket_api.py +++ b/swan_mcs/api/bucket_api.py @@ -317,11 +317,12 @@ def download_file(self, bucket_name, object_name, local_filename): ipfs_url = file.ipfs_url with open(local_filename, 'wb') as f: if file.size > 0: + logging.error('\033[31mThe file ipfs url: '+ipfs_url+'\033[0m') + logging.error('\033[31mThe file gateway: '+file.gateway+'\033[0m') data = urllib.request.urlopen(ipfs_url) if data: f.write(data.read()) - logging.info( - "\033[32mFile downloaded successfully\033[0m") + logging.info("\033[32mFile downloaded successfully\033[0m") return True else: logging.error('\033[31mDownload failed\033[0m') diff --git a/swan_mcs/api_client.py b/swan_mcs/api_client.py index a59d9dc..1b850e5 100644 --- a/swan_mcs/api_client.py +++ b/swan_mcs/api_client.py @@ -1,6 +1,6 @@ from swan_mcs.common.constants import * from swan_mcs.common.params import Params -import requests +import requests import json import logging from swan_mcs.common import utils, exceptions diff --git a/swan_mcs/object/bucket_storage.py b/swan_mcs/object/bucket_storage.py index 2014813..46e7e5d 100644 --- a/swan_mcs/object/bucket_storage.py +++ b/swan_mcs/object/bucket_storage.py @@ -30,7 +30,7 @@ def __init__(self, file_data, gateway = 'https://ipfs.io'): self.prefix = file_data["prefix"] self.size = file_data["size"] self.payloadCid = file_data["payload_cid"] - self.ipfs_url = gateway + '/ipfs/' + file_data["payload_cid"] + self.ipfs_url = gateway + '/ipfs/' + file_data["payload_cid"] # think there is an issue here self.pin_status = file_data["pin_status"] self.is_deleted = file_data["is_deleted"] self.is_folder = file_data["is_folder"] diff --git a/test/conftest.py b/test/conftest.py index 152a8ae..522d708 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -36,6 +36,7 @@ def shared_mock_api_client(): "data": {"jwt_token": "sample_token"}}) api_client = APIClient(api_key="sample_api_key", access_token="sample_access_token", chain_name="polygon.mumbai", is_calibration=True) + api_client.token=api_client.token['jwt_token'] return api_client @@ -221,6 +222,7 @@ def temp_dir(): shutil.rmtree(dirpath) + @pytest.fixture(scope="module", autouse=True) def delete_all_buckets(): bucket_api = BucketAPI(APIClient(api_key, access_token, chain_name)) @@ -231,4 +233,4 @@ def delete_all_buckets(): def pytest_sessionfinish(session, exitstatus): - delete_all_buckets() \ No newline at end of file + delete_all_buckets() diff --git a/test/test_mock_api_key_login.py b/test/test_mock_api_key_login.py index 13fb462..e6e8977 100644 --- a/test/test_mock_api_key_login.py +++ b/test/test_mock_api_key_login.py @@ -18,7 +18,7 @@ def test_api_key_login_success(self, mock_requests): "data": {"jwt_token": "sample_token"}}) api_client = APIClient(api_key="sample_api_key", access_token="sample_access_token", chain_name="polygon.mumbai", is_calibration=True) - token = api_client.token + token = api_client.token['jwt_token'] assert compare_digest(token, "sample_token") @pytest.mark.parametrize("api_key, access_token, chain_name", [