├── .github └── workflows │ ├── build.yml │ └── lint.yml ├── .gitignore ├── .idea ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── proto-python-course.iml ├── runConfigurations │ ├── clean.xml │ ├── generate.xml │ └── main.xml └── vcs.xml ├── .protolint └── .protolint.yml ├── Makefile ├── README.md ├── main.py ├── proto ├── complex.proto ├── enumerations.proto ├── maps.proto ├── oneofs.proto └── simple.proto └── requirements.txt /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build main branch 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - "*.py" 8 | - "Makefile" 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - "*.py" 13 | - "Makefile" 14 | 15 | jobs: 16 | build-win: 17 | runs-on: windows-2022 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: actions/setup-python@v3 21 | with: 22 | python-version: '3.x' 23 | 24 | - name: Install make 25 | run: choco install make 26 | 27 | - name: Install Protoc 28 | uses: arduino/setup-protoc@v1 29 | with: 30 | version: '3.x' 31 | 32 | - name: Setup venv 33 | run: | 34 | python -m venv venv 35 | pip install -r requirements.txt 36 | 37 | - name: Build 38 | run: make 39 | build-unix: 40 | runs-on: ${{ matrix.os }} 41 | 42 | strategy: 43 | matrix: 44 | os: [ubuntu-20.04, macos-11] 45 | steps: 46 | - uses: actions/checkout@v2 47 | - uses: actions/setup-python@v3 48 | with: 49 | python-version: '3.x' 50 | 51 | - name: Install Protoc 52 | uses: arduino/setup-protoc@v1 53 | with: 54 | version: '3.x' 55 | 56 | - name: Setup venv 57 | run: | 58 | python -m venv venv 59 | pip install -r requirements.txt 60 | 61 | - name: Build 62 | run: make -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint protobuf 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - "**/*.proto" 8 | pull_request: 9 | branches: [ main ] 10 | paths: 11 | - "**/*.proto" 12 | 13 | jobs: 14 | pr-check: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout source 18 | uses: actions/checkout@v1 19 | 20 | - name: Run protolint 21 | uses: plexsystems/protolint-action@v0.4.0 22 | with: 23 | configDirectory: .protolint -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *_pb2.py 3 | simple.bin 4 | venv 5 | requirements.txt-e -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/proto-python-course.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/clean.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations/generate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.protolint/.protolint.yml: -------------------------------------------------------------------------------- 1 | lint: 2 | rules: 3 | no_default: false 4 | add: 5 | - ENUM_FIELD_NAMES_PREFIX 6 | - ENUM_FIELD_NAMES_UPPER_SNAKE_CASE 7 | - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH 8 | - ENUM_NAMES_UPPER_CAMEL_CASE 9 | - FILE_NAMES_LOWER_SNAKE_CASE 10 | - FIELD_NAMES_LOWER_SNAKE_CASE 11 | - MPORTS_SORTED 12 | - MESSAGE_NAMES_UPPER_CAMEL_CASE 13 | - ORDER 14 | - PACKAGE_NAME_LOWER_CASE 15 | - RPC_NAMES_UPPER_CAMEL_CASE 16 | - SERVICE_NAMES_UPPER_CAMEL_CASE 17 | - REPEATED_FIELD_NAMES_PLURALIZED 18 | - QUOTE_CONSISTENT 19 | - INDENT 20 | - PROTO3_FIELDS_AVOID_REQUIRED 21 | - PROTO3_GROUPS_AVOID 22 | - MAX_LINE_LENGTH 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN_NAME = python3 2 | PROTO_DIR = proto 3 | 4 | ifeq ($(OS), Windows_NT) 5 | BIN = ${BIN_NAME}.exe 6 | else 7 | BIN = ${BIN_NAME} 8 | endif 9 | 10 | run: generate 11 | ${BIN} main.py 12 | 13 | generate: 14 | protoc -I${PROTO_DIR} --python_out=${PROTO_DIR} ${PROTO_DIR}/*.proto 15 | 16 | bump: 17 | sed -i -e 's/==/>=/g' requirements.txt 18 | ./venv/bin/python -m pip install -r requirements.txt --upgrade 19 | ./venv/bin/python -m pip freeze > requirements.txt 20 | 21 | clean: 22 | rm ${PROTO_DIR}/*_pb2.py 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # proto-python-course 2 | [![build main branch](https://github.com/Clement-Jean/proto-python-course/actions/workflows/build.yml/badge.svg)](https://github.com/Clement-Jean/proto-python-course/actions/workflows/build.yml) [![Lint protobuf](https://github.com/Clement-Jean/proto-python-course/actions/workflows/lint.yml/badge.svg)](https://github.com/Clement-Jean/proto-python-course/actions/workflows/lint.yml) 3 | 4 | ## COUPON: `START_OCT_2025` 5 | 6 | ## Notes 7 | 8 | ### `Windows` 9 | 10 | - I recommend you use powershell (try to update: [see](https://github.com/PowerShell/PowerShell/releases)) for following this course. 11 | - I recommend you use [Chocolatey](https://chocolatey.org/) as package installer (see [Install](https://chocolatey.org/install)) 12 | 13 | ### Build 14 | 15 | #### `Linux/MacOS` 16 | 17 | ```shell 18 | python -m venv venv 19 | source ./venv/bin/activate 20 | pip install -r requirements.txt 21 | make generate 22 | ``` 23 | 24 | #### `Windows - Chocolatey` 25 | ```shell 26 | choco install make 27 | python -m venv venv 28 | source ./venv/bin/activate 29 | pip install -r requirements.txt 30 | make generate 31 | ``` 32 | 33 | #### `Windows - Without Chocolatey` 34 | 35 | ```shell 36 | python -m venv venv 37 | source ./venv/bin/activate 38 | pip install -r requirements.txt 39 | protoc -Iproto --python_out=proto proto/*.proto 40 | ``` 41 | 42 | ### Run 43 | 44 | ``` 45 | python main.py 46 | ``` 47 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import google.protobuf.json_format as json_format 2 | 3 | import proto.complex_pb2 as complex_pb2 4 | import proto.enumerations_pb2 as enum_pb2 5 | import proto.maps_pb2 as maps_pb2 6 | import proto.oneofs_pb2 as oneofs_pb2 7 | import proto.simple_pb2 as simple_pb2 8 | 9 | 10 | def simple() -> simple_pb2.Simple: 11 | return simple_pb2.Simple( 12 | id=42, 13 | is_simple=True, 14 | name="My name", 15 | sample_lists=[3, 4, 5] 16 | ) 17 | 18 | 19 | def complex() -> complex_pb2.Complex: 20 | message = complex_pb2.Complex() 21 | message.one_dummy.id = 42 22 | message.one_dummy.name = "My name" 23 | message.multiple_dummies.add(id=43, name="My name 2") 24 | message.multiple_dummies.add(id=44, name="My name 3") 25 | message.multiple_dummies.add(id=45, name="My name 4") 26 | return message 27 | 28 | 29 | def enum(): 30 | return enum_pb2.Enumeration( 31 | eye_color=enum_pb2.EYE_COLOR_GREEN, 32 | # eye_color=1 33 | ) 34 | 35 | 36 | def oneof(): 37 | message = oneofs_pb2.Result() 38 | message.message = "message" 39 | print(message) 40 | 41 | message.id = 42 42 | print(message) 43 | 44 | 45 | def maps(): 46 | message = maps_pb2.MapExample() 47 | message.ids["myid"].id = 42 48 | message.ids["myid2"].id = 43 49 | message.ids["myid3"].id = 44 50 | print(message) 51 | 52 | 53 | def file(message): 54 | path = "simple.bin" 55 | 56 | print("Write to file") 57 | print(message) 58 | with open(path, "wb") as f: 59 | bytes_as_str = message.SerializeToString() 60 | f.write(bytes_as_str) 61 | 62 | print("Read from file") 63 | with open(path, "rb") as f: 64 | t = type(message) 65 | message = t().FromString(f.read()) 66 | 67 | print(message) 68 | 69 | 70 | def to_json(message): 71 | return json_format.MessageToJson( 72 | message, 73 | indent=None, 74 | # preserving_proto_field_name=True 75 | ) 76 | 77 | 78 | def from_json(json_str, type): 79 | return json_format.Parse( 80 | json_str, 81 | type(), 82 | ignore_unknown_fields=True 83 | ) 84 | 85 | 86 | if __name__ == "__main__": 87 | print(simple()) 88 | # print(complex()) 89 | # print(enum()) 90 | # oneof() 91 | # maps() 92 | # file(simple()) 93 | # json_str = to_json(complex()) 94 | # print(json_str) 95 | # print(from_json(json_str, complex_pb2.Complex)) 96 | # print(from_json('{"id": 42, "unknown": "test"}', simple_pb2.Simple)) 97 | -------------------------------------------------------------------------------- /proto/complex.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example.complex; 4 | 5 | message Dummy { 6 | int32 id = 1; 7 | string name = 2; 8 | } 9 | 10 | message Complex { 11 | Dummy one_dummy = 2; 12 | repeated Dummy multiple_dummies = 3; 13 | } -------------------------------------------------------------------------------- /proto/enumerations.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example.enumerations; 4 | 5 | enum EyeColor { 6 | EYE_COLOR_UNSPECIFIED = 0; 7 | EYE_COLOR_GREEN = 1; 8 | EYE_COLOR_BLUE = 2; 9 | EYE_COLOR_BROWN = 3; 10 | } 11 | 12 | message Enumeration { 13 | EyeColor eye_color = 1; 14 | } -------------------------------------------------------------------------------- /proto/maps.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example.maps; 4 | 5 | message IdWrapper { 6 | uint32 id = 1; 7 | } 8 | 9 | message MapExample { 10 | map ids = 1; 11 | } -------------------------------------------------------------------------------- /proto/oneofs.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example.oneofs; 4 | 5 | message Result { 6 | oneof result { 7 | string message = 1; 8 | uint32 id = 2; 9 | } 10 | } -------------------------------------------------------------------------------- /proto/simple.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example.simple; 4 | 5 | message Simple { 6 | uint32 id = 1; 7 | bool is_simple = 2; 8 | string name = 3; 9 | repeated int32 sample_lists = 4; 10 | } -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | protobuf==4.21.9 2 | --------------------------------------------------------------------------------