├── .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 |
4 |
5 |
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 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/generate.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
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 | [](https://github.com/Clement-Jean/proto-python-course/actions/workflows/build.yml) [](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 |
--------------------------------------------------------------------------------