This project is a demonstration and conceptual template from a Programming Language Design course, intended for educational purposes only. It is not designed to be a real product or tool.
- User Management: Create and manage users.
- Sheet Management: Users can create new sheets, print out their sheets, and change the content of their sheets.
- Access Control: Sheets have two access rights (read-only or editable). Users can share their sheets with other users.
- Arithmetic Operations: Sheets support rational arithmetic (
+
,-
,*
,/
). Handles rational numbers like123.456
,123
and operators like+
,-
,*
,/
. - Modular Access Control: Easily switch on/off access rights and sharing functionality by modifying specific parts of the code.
- Python Version: 3.12
To run the application, execute the following command in the command line:
python main.py
This will start the application and allow you to interact with it using the provided commands:
-
help
- Outputs the list of available commands.
-
user
<user_name>
- Creates a user with the specified
<user_name>
.
- Creates a user with the specified
-
sheet
<user_name>
<sheet_name>
- Creates a sheet named
<sheet_name>
for the user<user_name>
.
- Creates a sheet named
-
check
<user_name>
<sheet_name>
- Displays the content of the sheet named
<sheet_name>
for the user<user_name>
.
- Displays the content of the sheet named
-
patch
<user_name>
<sheet_name>
<row_number>
<col_number>
<number>
- Modifies the content at position (
<row_number>
,<col_number>
) of the sheet<sheet_name>
for the user<user_name>
to<number>
.
- Modifies the content at position (
-
chmod
<user_name>
<sheet_name>
<readonly/editable>
- Changes the access rights of the sheet
<sheet_name>
for the user<user_name>
to either read-only or editable.
- Changes the access rights of the sheet
-
share
<user_name_a>
<sheet_name>
<user_name_b>
- Shares the sheet
<sheet_name>
from user<user_name_a>
to user<user_name_b>
.
- Shares the sheet
Main program which decorates commands in ArgumentShell
to define the behavior of each command.
Safe arithmetic evaluation:
- Parses and evaluates arithmetic expressions securely.
- Supports operations:
+
,-
,*
,/
,%
,**
,//
, scientific notation, and other number bases.
Defines data types and operations:
-
User
- Attributes:
name
(string)
- Attributes:
-
Sheet
- Attributes:
id
(string),data
(list[list[float]]) - Behavior:
patch(row, column, value)
modifies the data.
- Attributes:
-
Permission (Enum)
- Values:
READONLY
,EDITABLE
- Values:
-
SheetPermission
- Attributes:
is_owner
(bool) - Behavior:
post(sheets, manager, username, sheetid)
get(sheets, sheetid)
patch(sheets, sheetid, row, column, value)
chmod(manager, username, sheetid, state)
- Attributes:
-
SheetReadOnly (extends SheetPermission)
- Behavior:
patch(sheets, sheetid, row, column, value)
- Behavior:
-
SheetEditable (extends SheetPermission)
- Behavior:
patch(sheets, sheetid, row, column, value)
- Behavior:
-
SheetDatabase
- Attributes:
users
(dict),sheets
(dict),manager
(dict) - Behavior:
get_user(username)
post_user(username)
get_sheet(user, sheetid)
post_sheet(user, sheetid)
patch_sheet(user, sheetid, row, column, value)
chmod(user1, user2, sheetid, state)
- Attributes:
Command management:
- Adds commands to
ArgumentShell
and parser. - Parses and executes the corresponding functions for each command.
To disable chmod
and share
functionality:
- Remove or comment out the corresponding functions in
main.py
. - Verify by running
help
or the specific command.
- Features: Encapsulation, Inheritance, Polymorphism, Reduced maintenance and extension efforts.
- Application:
- Classes are encapsulated, accessed only through provided interfaces.
readonly
andeditable
inherit fromPermission
and overridepatch
for polymorphism inSheetDatabase
.- Use of
typing.Protocol
inSheetPermission
class to define a common interface without requiring inheritance. This allows for more flexible and decoupled code design, as different classes can implement the protocol without being tightly bound to a specific class hierarchy.
- Features: Code that writes or manipulates other code, typically at compile time or runtime.
- Application in
sugar.py
:- Utilizes decorators like
@app.command
to dynamically add commands to theArgumentShell
. - Inspects type annotations at runtime to ensure proper command parsing and execution.
- Example from
sugar.py
andmain.py
:@app.command
decorator inspects function signatures and type annotations to register commands dynamically.- This allows for flexible command definitions and ensures that type constraints are enforced when commands are executed.
- Utilizes decorators like
- Features: Control flow by user actions or messages, Dynamic callback setting, Asynchronous execution, Low coupling.
- Potential Application:
- Use buttons instead of command input.
- Objects publish events to observers (Observer Pattern).
- Features: Encapsulates different behaviors, easy to switch and extend, avoids excessive if-else.
- Application:
- Define
Permission
base class withreadonly
andeditable
inheriting. - Different
patch
behaviors implemented inreadonly
andeditable
. manager
executes stored permissions (polymorphism).- Switch behaviors by assigning corresponding permissions to
manager
.
- Define
- Features: Observers notified of changes in the observable object.
- Potential Application:
- Users with access have their own sheet copy.
user
implementsobserver
,sheet
implementsobservable
.- Users register as observers to the sheet.
- Changes notify all observers to update.
No real bugs were encountered that required a debugger, but there are still some important points to share.
Implementing detailed permission assessment raised some questions. Specifically, if an owner changes their permission to read-only, should they be able to change it back to editable? If allowed, since the default permission is read-only, anyone could modify the permission to editable, compromising security. If not allowed, the owner can never regain access permissions, rendering the sheet unmodifiable.
We temporarily solved this by adding an owner flag to the permission object, which restricts the chmod
behavior to be callable only by the owner.
Safely evaluating an expression via Python's built-in eval
is not possible, so a custom implementation is necessary. Parsing a binary operation is straightforward but traditionally not extensible.
We used the built-in ast
module and the match
statement to validate that the syntax is either a numeric binary operation or a numeric constant. This approach is interesting and worth checking out.
Python's built-in cmd
module supports shell-like programs but can access the real shell, which can be dangerous. Other third-party shell libraries exist but hardly fit this scenario, so we rebuilt the shell from scratch.
Introducing SUGAR
(Simple Utility for Generating Argparse-based Runner). As its name suggests, it uses another built-in library, argparse
, a CLI library, as the parser for each command.
Furthermore, it inspects annotations at runtime, as described in the metaprogramming section. Thus, we can easily add and remove commands by simply commenting out one line of code, without needing to modify the parser when parameters change. This approach is inspired by Fire
and Typer
, two well-known Python third-party CLI libraries.
How did I come up with this? I frequently encounter the need for a shell-like library in everyday coding, but third-party libraries sometimes do not match my requirements. Submitting a feature request can be time-consuming, so I created SUGAR
. It is intended to be published to PyPI once the basic features are completed.