【Python】Python ~ 基本編 / リスト・あれこれ ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/10/12/084943

の続き。

リストの記事が長くなったので、整理して分冊。

また、Pythonの資格の問題ででてきたスライスなど
あまり使っていなかったものを整理。

Python に関する資格
https://dk521123.hatenablog.com/entry/2019/12/17/225829

目次

【1】間違えやすい文法
 1)スライス
 2)負のインデックス
 3)リスト内包表記(List comprehensions)
【2】リスト・あれこれ
 1)空リストの定義とその判定
 2)ソート
 3)要素のクローン
 4)要素のカウント
 5)合成(+)
 6)分割(文字列⇒リスト)
 7)join(リスト⇒文字列)
 8)typing
 9)reprlib
 10)抽出と除外

【1】間違えやすい文法

1)スライス

[start:end:step] のように値が指定できる

例1

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(a[2:8]) # [2, 3, 4, 5, 6, 7]
print(a[:5]) # [0, 1, 2, 3, 4]
print(a[5:]) # [5, 6, 7, 8, 9]
print(a[2:8:2]) # [2, 4, 6]

例2

values = "Hello World!!!"

print(values[:5])
print(values[6:11])

# 出力結果
# Hello
# World

https://qiita.com/okkn/items/54e81346d8f35733ab5e

2)負のインデックス

* 後ろから数えて何番目かという指定になる

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(a[-1]) # 9
print(a[-2]) # 8

3)リスト内包表記(List comprehensions)

サンプル

# ↓のような書き方を「リスト内包表記(List comprehensions)」という
list = [x**2 for x in range(10)]
print(list) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# ネストも可能
list2 = [(x, y) for x in range(2) for y in range(3)]
print(list2) # (0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]   

【2】リスト・あれこれ

 1)空リストの定義とその判定

サンプル

empty1_list = []
# [] と表示
print(empty1_list)
if not empty1_list:
  print("リストは空です")

empty2_list = list()
print(empty2_list)
if len(empty2_list) == 0:
  print("リストは空ですYO")
if empty2_list == []:
  print("リストは空ですYOYO")

https://qiita.com/yonedaco/items/d0f65ca3dad2e085a51d

2)ソート

サンプル

# sort() : 中身そのものがソートする
number = [1,5,3,4,2]
number.sort()
print(number)  # [1, 2, 3, 4, 5]が出力される。

# sorted() : 変数の中身そのものは変更しない
number = [1,5,3,4,2]
print(sorted(number))  # [1, 2, 3, 4, 5]が出力される。
print(number)  # [1, 5, 3, 4, 2]が出力される。

# 昇順/降順
print(sorted(words, reverse=True))
print(sorted(words, reverse=Flase))

補足:辞書リストのソート

以下の関連記事の「■ 辞書リストをソートする」を参照のこと

https://dk521123.hatenablog.com/entry/2019/10/27/100014

 3)要素のクローン

* [:]で行う

サンプル

fruits_clone = fruits[:]

4)要素のカウント

サンプル

name_list = ['Tom', 'Sam', 'Mike', 'Sam', 'Kevin', 'Sam', 'Mike', 'Sam',]

# count('【カウントしたい要素内容】')
print(name_list.count('Mike')) # 2

5)合成(+)

* リスト同士で「+」することができる

サンプル

first_list = [1, 2, 3]
second_list = [4, 5, 6]

total_list = first_list + second_list
# [1, 2, 3, 4, 5, 6]
print(total_list)

6)分割(文字列⇒リスト)

* split("【区切り文字】")を使う

サンプル

hello = "Hello World !!"
print(hello.split(" ")) # ['Hello','World','!!']が出力される。

7)join(リスト⇒文字列)

list = ['Mike', 'Tom', 'Sam']
result = '\n'.join(list)
print(result)

出力結果例

Mike
Tom
Sam

8)typing

https://docs.python.org/ja/3/library/typing.html

* 何もしない状態では、
 以下のようにListの中身の型を定義することはできない
 => 「from typing import List」を使えば大丈夫
* Typing モジュールに詳細は、以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2021/12/23/231559

修正前(ダメな例・一部抜粋)

sample_list = [1, 3, 2, 5, 4]

def print_list(sample_list: list[int]) -> None: # ここでエラー

修正後

from typing import List

def print_list(sample_list: List[int]) -> None:
  for input in sample_list:
    print("input = {}".format(input))

if __name__ == '__main__':
  sample_list = [1, 3, 2, 5, 4]
  print_list(sample_list)

9)reprlib

* 出力文字列の長さを制限する
 => デバッグログとして使えるかも

https://docs.python.org/ja/3/library/reprlib.html
https://www.st-hakky-blog.com/entry/2017/11/28/144751
サンプル

import reprlib

values = [i for i in range(10)]

print(values)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(reprlib.repr(values))
# [0, 1, 2, 3, 4, 5, ...]

10)抽出と除外

* 別の方法としては、「filter / lambda」があるが
 そちらの詳細は、以下の関連記事を参照のこと

Python ~ 基本編 / ラムダ lambda ~
https://dk521123.hatenablog.com/entry/2019/09/23/000000

サンプル

target_list = [
  "table1",
  "table2",
  "table3",
  "table4",
  "table1 -> table2",
  "table2 -> table3",
  "table2 -> table4"
]

# 抽出 (in)
list = [line for line in target_list  if 'table3' in line]
print(list)

print('*******************')

# 除外(not in)
list = [line for line in target_list  if 'table3' not in line]
print(list)

参考文献

https://www.atmarkit.co.jp/ait/articles/1905/31/news015_2.html

関連記事

Python ~ 基本編 / リスト ~
https://dk521123.hatenablog.com/entry/2019/10/12/084943
Python ~ 基本編 / スライス操作 ~
https://dk521123.hatenablog.com/entry/2020/11/14/000000
Python ~ 基本編 / 文字列 ~
https://dk521123.hatenablog.com/entry/2019/10/12/075251
Python ~ 基本編 / 型指定・Typing ~
https://dk521123.hatenablog.com/entry/2021/12/23/231559
Python ~ 基本編 / ラムダ lambda ~
https://dk521123.hatenablog.com/entry/2019/09/23/000000
Python に関する資格
https://dk521123.hatenablog.com/entry/2019/12/17/225829

【AWS】Amazon S3 ~ アクセス制御 / IAM Policy 編 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2020/09/29/165636

の続き。

今回は、IAM Policy を使ったアクセス制御について、メモする。
これを細かく設定できれば、セキュリティ強化にかなり役立ちそう。

目次

【0】実装前に
【1】Read Onlyにする
【2】特定のS3バケットのみしかアクセスできないようにする
【3】特定の IAM ロールのみアクセスできるにする
【4】特定の VPC エンドポイントへのアクセスのみ制限

【0】実装前に

* 使用できるAction は、以下の公式サイトを参照のこと。

公式サイト:Action 一覧
https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations.html

* 以下の公式サイトのチュートリアル / サンプル もみておくといいかも。

公式サイト:チュートリアル / サンプル
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/walkthrough1.html
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-policies-s3.html

注意

* 明示的な拒否ステートメント(Deny)は、許可ステートメント(Allow)よりも優先される

【1】Read Onlyにする

サンプル

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ReadOnly",
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Resource": "*"
    }
  ]
}

【2】特定のS3バケットのみしかアクセスできないようにする

https://qiita.com/komazawa/items/988c346274666023d9dd

にある以下の設定に注意。
~~~~~~
bucketそのものに対するアクセスと、
bucket配下のオブジェクトに対するアクセス
両方を指定する必要があるらしい
~~~~~~

サンプル

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "S3PolicySample",
          "Effect": "Allow",
          "Action": [
              "s3:GetObject",
              "s3:PutObject",
              "s3:GetObjectAcl",
              "s3:PutObjectAcl",
              "s3:DeleteObject",
              "s3:ListAllMyBuckets",
              "s3:GetBucketLocation",
              "s3:ListBucket"
          ],
          "Resource": [
                "arn:aws:s3:::your-bucket-name",
                "arn:aws:s3:::your-bucket-name/*"
          ]
      }
  ]
}

【3】特定の IAM ロールのみアクセスできるにする

https://dev.classmethod.jp/articles/s3-bucket-acces-to-a-specific-role/

が参考になる

サンプル

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "S3PolicySample",
           "Effect": "Deny",
           "Principal": "*",
           "Action": "s3:*",
           "Resource": [
                "arn:aws:s3:::your-bucket-name",
                "arn:aws:s3:::your-bucket-name/*"
           ]
           "Condition": {
               "StringNotLike": {
                   "aws:userId": [
                       "xxxxxxxxxxxxxxxxxxxxxx:*"
                  ]
               }
           }
      }
  ]
}

【4】特定の VPC エンドポイントへのアクセスのみ制限

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies-vpc-endpoint.html
https://dev.classmethod.jp/articles/s3-access-from-specific-ip-and-vpc/

が参考になる

サンプル

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "S3-Access-to-specific-VPCE-only",
           "Effect": "Deny",
           "Principal": "*",
           "Action": "s3:*",
           "Resource": [
                "arn:aws:s3:::your-bucket-name",
                "arn:aws:s3:::your-bucket-name/*"
           ]
           "Condition": {
               "StringNotEquals": {
                    "aws:sourceVpc": [
                       "vpc-xxxxxxxxxxxxxxxxx"
                  ]
               }
           }
      }
  ]
}

参考文献

https://qiita.com/komazawa/items/988c346274666023d9dd
https://dev.classmethod.jp/articles/what-permissions-are-needed-for-s3-sync/
https://qastack.jp/programming/38774798/accessdenied-for-listobjects-for-s3-bucket-when-permissions-are-s3
公式サイト
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/list_amazons3.html
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/using-with-s3-actions.html
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-access-denied-listobjects-sync/

関連記事

Amazon S3 ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2017/03/06/212734
Amazon S3 ~ アクセス制御編 ~
https://dk521123.hatenablog.com/entry/2020/09/29/165636
IAM ~ IAM Policy 編 ~
https://dk521123.hatenablog.com/entry/2020/09/30/133123
Amazon EMR に関するトラブルシューティング
https://dk521123.hatenablog.com/entry/2020/08/05/144724

【トラブル】【AWS】boto3 AWS Glue API のトラブル ~ trigger全般 編 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2020/01/16/205331

が長くなり、別ケースの例外メッセージもあったので分冊。

今回は、boto3 AWS Glue API の trigger全般 のトラブルを纏める

目次

【1】create_trigger() コール時に例外が発生する
【2】create_trigger() コール時に例外「State cannnot be null or empty」が発生する
【3】get_trigger() 実行時 に例外「ThrottlingException」が発生する

【1】create_trigger() コール時に例外が発生する

create_trigger() を使用した際に、以下の「エラー内容」が表示された

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.create_trigger

エラー内容

Case1

botocore.exceptions.ClientError: An error occurred (InternalError)
 when calling the CreatTrigger operation (reached max retries: 4):
... 略 ...
TypeError: __init__() missing 1 required positional arguments: 'operation_name'

Case2

An error occurred (EntityNotFoundException)
 when calling the CreateTrigger operation: Entity not found

原因

create_trigger() の WorkflowName (関連付けるワークフロー名)の指定の仕方が間違っていた
(めちゃくちゃはまった。。。)

サンプル抜粋

response = client.create_trigger(
    Name='sample_trigger',
    WorkflowName='sample_workflow', # ★ここのワークフロー名が存在しない名前を指定していた★
    ....

解決策

WorkflowName を正しい指定にした

【2】create_trigger() コール時に例外「State cannnot be null or empty」が発生する

Crawlerイベント設定において、
create_trigger() コール時に以下の「エラー内容」が発生した。

例外には「State cannnot be null or empty」と記載されているが、
設定には、「State: 'SUCCEEDED'」が記載されている。

エラーが発生したYAMLファイル

Name: 'sample-trigger-for-crawler'
Description: 'This is a sample trigger for a crawler'
WorkflowName: 'sample-workflow'
Type: 'CONDITIONAL'
Predicate:
  Logical: 'ANY'
  Conditions:
    - LogicalOperator: 'EQUALS'
      CrawlerName: 'sample-crawler'
      State: 'SUCCEEDED'
Actions:
  - JobName: 'sample-job'
    Arguments:
      --success_param: '0'
StartOnCreattion: True
Tags:
  Name: 'sample-trigger-for-crawler'

エラー内容

An error occurred (InvalidInputException) when calling the CreateTrigger operation:
State cannnot be null or empty, choose from one of the following crawler state:
[SUCCEEDED, FAILED, CANCELLED]

原因

State: 'SUCCEEDED'
ではなく
CrawlState: 'SUCCEEDED'
だった

対応策

パラメータを修正

エラーが発生したYAMLファイル

Name: 'sample-trigger-for-crawler'
Description: 'This is a sample trigger for a crawler'
WorkflowName: 'sample-workflow'
Type: 'CONDITIONAL'
Predicate:
  Logical: 'ANY'
  Conditions:
    - LogicalOperator: 'EQUALS'
      CrawlerName: 'sample-crawler'
      CrawlState: 'SUCCEEDED'
Actions:
  - JobName: 'sample-job'
    Arguments:
      --success_param: '0'
StartOnCreattion: True
Tags:
  Name: 'sample-trigger-for-crawler'

【3】get_trigger() 実行時 に例外「ThrottlingException」が発生する

エラー内容

An error occurred (ThrottlingException)
 when calling the GetTrigger operation (reached max retries: 4): Rate exceeded

原因

ThrottlingException は、APIコールレートの上限を超過した場合に発生する。
(なので、『(reached max retries: 4): Rate exceeded』って書いてある)

対応策

リトライする。(以下のサンプルを参照)

サンプル

import boto3
try:
    from botocore.exceptions import BotoCoreError, ClientError
except ImportError:
    pass

MAX_RETRY_COUNT = 20
WAIT_TIME_FOR_RETRY = 15

def has_trigger(glue_client, trigger_name, retry_count=1):

    has_workflow = False
    try:
        response = glue_client.get_trigger(
            Name=trigger_name)
        has_workflow = True
    except(BotoCoreError, ClientError) as ex:
        error_code = ex.response['Error']['Code']
        if error_code == 'EntityNotFoundException':
            has_workflow = False
        elif error_code == 'ThrottlingException':
            if retry_count < MAX_RETRY_COUNT:
                print("Throttling Exception Occured. Attempt No.: " + str(tries))
                time.sleep(WAIT_TIME_FOR_RETRY)
                return has_trigger(glue_client, trigger_name, retry_count + 1)
            else:
                print("Attempted {} Times But No Success.".format(MAX_RETRY_COUNT))
                raise ex
        else:
            raise ex

if __name__ == '__main__':
    glue_client = boto3.client('glue')
    target_trigger_name = 'YOUR_TRIGGER_NAME'
    print('Exists the trigger [{}] : [{}]'.format(
         target_trigger_name, has_trigger(glue_client, target_trigger_name)))

参考文献

https://stackoverflow.com/questions/30104286/throttlingexception-aws-api

関連記事

boto3 AWS Glue API のトラブル ~ scheduled trigger編 ~
https://dk521123.hatenablog.com/entry/2020/01/16/205331
AWS Glue ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/10/01/221926
AWS Glue ~ Boto3 / 入門編 ~
https://dk521123.hatenablog.com/entry/2019/10/14/000000
AWS Glue ~ Boto3 / 基本編 ~
https://dk521123.hatenablog.com/entry/2021/04/17/001930
AWS Glue ~ Boto3 / クローラ編 ~
https://dk521123.hatenablog.com/entry/2021/04/16/135558
boto3 AWS Glue API のトラブル ~ scheduled trigger編 ~
https://dk521123.hatenablog.com/entry/2020/01/16/205331
boto3 AWS Glue API のトラブル ~ job/crawler編 ~
https://dk521123.hatenablog.com/entry/2020/02/05/223307
AWS Glue のトラブル ~ job編 - [1] ~
https://dk521123.hatenablog.com/entry/2019/10/25/232155
AWS Glue のトラブル ~ job編 - [2] ~
https://dk521123.hatenablog.com/entry/2020/10/12/152659
AWS Glue のトラブル ~ job編 - [3] ~
https://dk521123.hatenablog.com/entry/2021/02/16/145848
AWS Glue のトラブル ~ crawler編 ~
https://dk521123.hatenablog.com/entry/2020/05/07/144132