Skip to content

Commit b692951

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Add PyCEL codelab
PiperOrigin-RevId: 853861620
1 parent 2a91a16 commit b692951

3 files changed

Lines changed: 1959 additions & 0 deletions

File tree

codelab/codelab.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# This file contains code that demonstrates common CEL features.
16+
# This code is intended for use with the PyCEL Codelab
17+
18+
"""This file contains code that demonstrates common CEL features.
19+
20+
This code is intended for use with the PyCEL Codelab.
21+
"""
22+
23+
# pylint: disable=unused-import
24+
import datetime
25+
import json
26+
import pprint
27+
from google.rpc.context import attribute_context_pb2
28+
from py_cel import py_cel as cel
29+
from py_cel.ext import ext_math
30+
from py_cel.ext import ext_string
31+
# pylint: enable=unused-import
32+
33+
34+
def exercise1():
35+
"""exercise1 evaluates a simple literal expression: "Hello, World!".
36+
37+
Compile, eval, profit!
38+
"""
39+
40+
print("=== Exercise 1: Hello World ===\n")
41+
42+
print()
43+
44+
45+
def exercise2():
46+
"""exercise2 shows how to declare and use variables in expressions.
47+
48+
Given a request of type google.rpc.context.AttributeContext.Request
49+
determine whether a specific auth claim is set.
50+
"""
51+
print("=== Exercise 2: Use variables in a function ===\n")
52+
53+
print()
54+
55+
56+
def exercise3():
57+
"""exercise3 demonstrates how CEL's commutative logical operators work.
58+
59+
Construct an expression which checks if the `request.auth.claims.group`
60+
value is equal to admin or the `request.auth.principal` is
61+
`user:me@acme.co`. Issue two requests, one that specifies the proper
62+
user, and one that specifies an unexpected user.
63+
"""
64+
print("=== Exercise 3: Logical AND/OR ===\n")
65+
66+
print()
67+
68+
69+
def exercise4():
70+
"""exercise4 demonstrates the use of standard extensions."""
71+
72+
print("=== Exercise 4: Standard extensions ===\n")
73+
74+
print()
75+
76+
77+
def exercise5():
78+
"""exercise5 demonstrates how to extend CEL with custom functions.
79+
80+
Declare a `contains` member function on map types that returns a boolean
81+
indicating whether the map contains the key-value pair.
82+
"""
83+
84+
print("=== Exercise 5: Customization ===\n")
85+
86+
print()
87+
88+
89+
def contains_key_value(cel_map, key, value):
90+
return key in cel_map and cel_map[key] == value
91+
92+
93+
def exercise6():
94+
"""exercise6 covers how to build complex objects as CEL literals.
95+
96+
Given the input now, construct a JWT with an expiry of 5 minutes.
97+
"""
98+
print("=== Exercise 6: Building JSON ===\n")
99+
100+
print()
101+
102+
103+
def value_to_json(value: cel.Value):
104+
"""value_to_json converts the CEL type to a JSON representation."""
105+
match value.type():
106+
case cel.Type.MAP:
107+
out = {}
108+
for key, val in value.value().items():
109+
out[key] = value_to_json(val)
110+
return out
111+
case cel.Type.TIMESTAMP:
112+
return value.value().isoformat()
113+
# This conversion is not exhaustive. To fully support JSON conversion,
114+
# we would need to handle other types such as cel.Type.DURATION and
115+
# cel.Type.LIST
116+
case _:
117+
return str(value.plain_value())
118+
119+
120+
def exercise7():
121+
"""exercise7 describes how to build proto message types within CEL.
122+
123+
Given an input jwt and time now construct a
124+
google.rpc.context.AttributeContext.Request with the time and auth
125+
fields populated according to the
126+
https://github.com/googleapis/googleapis/blob/master/google/rpc/context/attribute_context.proto
127+
specification.
128+
"""
129+
130+
print("=== Exercise 7: Building Protos ===\n")
131+
132+
print()
133+
134+
135+
def main() -> None:
136+
exercise1()
137+
exercise2()
138+
exercise3()
139+
exercise4()
140+
exercise5()
141+
exercise6()
142+
exercise7()
143+
144+
145+
if __name__ == "__main__":
146+
main()

0 commit comments

Comments
 (0)