Skip to content

Commit

Permalink
change import statements and updated install script
Browse files Browse the repository at this point in the history
change import statements and updated install script to support both python2 and python3 virtual environments

The change in the import statements is required to allow the extension to run properly under the python3 virtual environment for Klipper

Install script was updated and reorganized;

Added the following functions to the install script:
validate_printer_config_dir function, change_printer_config_dir function, check_env_version, validate_python3_installed,
change_py3, check_existing, create_requirements_file, prompt_user_update, validate_user_response,
copy_moonraker_update_file, and create_moonraker_file

Since this install script must handle both python2 and python3 virtual environments the install script will generate
the following files while the script is running based on the version of python running in Klipper virtual environment:
requirements.txt and extended_template_update.conf

The install script will now prompt the user to see if they want this extension automatically updated via moonraker's update manager.
If they answer Yes, then the install script will append an [include statement] to the EOF for the moonraker.conf
and save the extended_template_update.conf file to the printer's config directory.

Since moonraker changed directory structures, this install script will validate the printer's config file directory.
If the user is in python2 virtual env then the printer config directory should be /home/pi/klipper_config
If the user is in python3 virtual env then the printer config directory should be /home/pi/printer_data/config

This script defaults to a printer config directory of /home/pi/printer_data/config

Since this install script can now detect when this extension has already been installed, then need for another
script file for updates in no longer necessary.  This install scripts' function called check_existing will produce
a 1 if the symbolic links to the .py files already exists.  If the symbolic links are not present then check_existing
will return a 0.  This logic is used to stop the script reinstalling the additional software packages after this
extension has been installed.

Since the moonraker update manager will automatically restart Klipper after an update, this script prevents
Klipper from restarting once the extension has been installed.

When an moonraker update does occur this script will re-verify all the directories and refresh the symbolic
links to this extensions .py files.

choose a different instantance variable name for the class in the module

Removed unnecessary spaces from the files

ensure the execute bit is set for install.sh file
  • Loading branch information
GadgetAngel committed Feb 3, 2023
1 parent 5b8d687 commit 62bf23b
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 155 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.vscode
.old
**.pyc
4 changes: 2 additions & 2 deletions extended_macro/delayed_extended.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
#

import logging
import delayed_gcode
from .delayed_gcode import DelayedGcode

######################################################################
# Extended Delayed GCode macro
######################################################################
#
# Inherits DelayedGcode from delayed_gcode.py
# Only changes the template objects
class ExtendedDelayedGcode(delayed_gcode.DelayedGcode):
class ExtendedDelayedGcode(DelayedGcode):
def __init__(self, config):
self.printer = config.get_printer()
self.reactor = self.printer.get_reactor()
Expand Down
2 changes: 1 addition & 1 deletion extended_macro/extended_macro.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(self, printer, env, name, script):
raise printer.config_error(msg)

# Inherits PrinterGCodeMacro from gcode_macro.py
# Code added to utilize
# Code added to utilize
class ExtendedPrinterGCodeMacro(PrinterGCodeMacro, object): #Dummy `object` required due to the Python 2 requirement for using super()
def __init__(self, config):
super(ExtendedPrinterGCodeMacro, self).__init__(config)
Expand Down
48 changes: 24 additions & 24 deletions extended_macro/extended_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import flatten_dict

# DEFAULTS
# The default imports to be loaded by extended_template.
# The default imports to be loaded by extended_template.
# These do not need to be defined by the user in their config file
# If there is a name collision, the default imports will be given priority
# while the user defined functions are renamed with an underscore.
#
#
# For example, if the user were to define their own function named `list` (the same name as a default below),
# the user defined `list` will be renamed to `_list`.
DEFAULTS = {
Expand Down Expand Up @@ -49,7 +49,7 @@ def __init__(self, yaml_path, config):

with open(yaml_path, 'r') as f:
self.yaml = yaml.load(f, Loader=yaml.Loader)

func_yaml = self.yaml.get('functions',{})
filter_yaml = self.yaml.get('filters', {})
self._funcs = self._import_function_dict(func_yaml)
Expand All @@ -58,7 +58,7 @@ def __init__(self, yaml_path, config):
# Loops through each item in the config, passes
# the data off to _import_function which will return
# the actual function if it exists, and then adds
# each function to the function dictionary so they can
# each function to the function dictionary so they can
# be added by extended_macro to the Jinja environment

def GetFunctions(self):
Expand Down Expand Up @@ -112,19 +112,19 @@ def get_macro(self, macro_name):
macro = self.printer.lookup_object('extended_macro %s' % (macro_name))
except:
macro = self.printer.lookup_object('gcode_macro %s' % (macro_name))

else:
macro = self.printer.lookup_object(macro_name)

return macro

# update_gcode_variable
#
# Set the value of any GCode Variable for another (or the current) macro.
# Set the value of any GCode Variable for another (or the current) macro.
#
# Main differences between SET_GCODE_VARIABLE:
# * Can only be called in a macro
# * Can update any variable, not just literals.
# * Can update any variable, not just literals.
# * Does not require running through the interpreter; instead is only run inside Python
#
def update_gcode_variable(self, macro_name, variable, value):
Expand All @@ -144,7 +144,7 @@ def call_macro(self, macro_name, **params):
kwparams['params'] = params
macro.template.run_gcode_from_command(kwparams)

# update_dict
# update_dict
#
# Allows for updating a nested dictionary by passing a list, set, or tuple of keys.
# If the set of keys do not lead to a valid existing item, the keys will be created.
Expand Down Expand Up @@ -177,7 +177,7 @@ def __init__(self, config):
self.printer = self.config.get_printer()
self.gcode = self.printer.lookup_object('gcode')
self.Log = Logger(config)

self.config_path = config.get('path', None)
self.Loader = self._get_loader()
self.Functions = self._import_functions()
Expand All @@ -203,14 +203,14 @@ def _import_functions(self):
else:
u_key = key
all_funcs[u_key] = val

return all_funcs

def _get_loader(self, ext=None):
loader = None
if ext is None:
ext = self.config_path.split('.')[-1]

for l in LOADERS:
c_ext = l['extensions']

Expand All @@ -233,7 +233,7 @@ def _load_defaults(self):
loader = self._get_loader('default')
funcs = self._load_functions(loader)
return funcs

def _load_filters(self):
return self.Loader.GetFilters()

Expand All @@ -246,43 +246,43 @@ def _load_functions(self, loader=None):
return funcs, defaults_loaded

def _insert_function(self, func_name, func):
if func_name in self.Functions:
if func_name in self.Functions:
func_name = '_%s' % func_name

def load_config(config):
return PythonFunction(config)

# LOADERS
# The definitions in this list will be used to determine the proper loader for the extensions given
#
# Since different loaders might need or want different methods of parsing the file,
#
# Since different loaders might need or want different methods of parsing the file,
# the script expects that the loader is a function, not a class. The function should
# process the config file and return a dictionary with the jinja function name as the key
# and the actual Python function as the value
#
#
# The loader for DEFAULTS should be defined with an extension of ['default']
# This loader will be ignored if the property loader.DefaultsLoaded property is true (see below)
#
#
# Definition: {'extensions': <collection_or_string>, 'loader': <class>}
#
# Arguments received:
#
# Arguments received:
# * config_path: Path to config set in [extended_template]
# * config: Config object received from Klipper
#
# Required Properties and Functions:
# * loader.DefaultsLoaded <property>: <bool>
# - If True, it is assumed the loader has loaded the defaults listed below.
# - If True, it is assumed the loader has loaded the defaults listed below.
# - If False, assumes the loader has not loaded the defaults listed below.
# - It is suggested that the Loader should never process defaults unless:
# * The user defines the defaults in the config file
# * The loader defines it's own defaults
# * Any other scenario where it's better to load the defaults by the loader instead of separately
# * loader.GetFunctions(self) <function> = <dict>
# * loader.GetFunctions(self) <function> = <dict>
# - Loads user-defined functions.
# * Optionally,
# * Optionally,
# - Returns schema: {defined_function_name_for_jinja <str>: function <callable>}
#
#
#
#
LOADERS = [
{
'extensions': ['yaml','yml'],
Expand Down
60 changes: 28 additions & 32 deletions extended_macro/readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# extended_macro
# Extended_Template
---
* Allow the use of custom Python functions in your Klipper macros by defining the functions in a YAML config file
* By default includes many additional modules and functions. See below for more information.
Expand All @@ -9,27 +9,24 @@

**Do not blindly download Python scripts, both for use in your macros and this script itself.** Read the script and ensure you understand what is going on. The scripts can be powerful and useful, but they can also be dangerous. If the script looks questionable, dangerous, or too confusing, it's better to assume that it is malicious.

**Installation:**
1. Write down the location of the following directories:
**What will happen when you run the Installation script:**
1. The script will determine if the following directories exist:
* Klipper Extras: Usually located at `/home/USER/klipper/klippy/extras`.
* Klippy Virtual Environment `bin` directory: Usually located at `/home/USER/klippy/bin`
2. Clone this repository or download `extended_macro.py`, `extended_template.py`, and `requirements.txt`
3. Move `extended_macro.py` and `extended_template.py` to your Klipper Extras folder.
4. Move `requirements.txt` to your home directory.
5. Run the following command, substituting `${KLIPPY_ENV}` with the Klippy Virtual Environment bin directory:

```
${KLIPPY_ENV}/pip install -r ${HOME}/requirements.txt
```
2. It will clone this repository; the following files will be downloaded:
`extended_macro.py`, `extended_template.py`, and `delayed_extended.py`
3. The script will install additional software if this extension has not been installed before
4. The script creates a symbolic link from the clone Repo to the Klipper Extras folder for the following files:
`extended_macro.py`, `extended_template.py` and `delayed_extended.py`
5. If Klipper needs to be restarted the script will cause a Klipper restart.

---
**Setup:**

1. In your Klipper config, add the following section. Nothing more is needed if you do not plan on using your own Python scripts:
```
```INI
[extended_template]
```

---
**Adding your own Python functions**

Expand All @@ -42,14 +39,16 @@ ${KLIPPY_ENV}/pip install -r ${HOME}/requirements.txt
---
**Usage:**

See the examples folder for more guidance.
See the examples' folder for more guidance.

When defining the macro, use `extended_macro` as the config name instead of `gcode_macro`. To use your function, you will wrap the name with curly brackets (`{gcode_function_name_goes_here}`).

When defining the macro, use `extended_macro` as the config name instead of `gcode_macro`. To use your function, you will wrap the name with curly brackets (`{gcode_function_name_goes_here}`).
When you need the macro to be used on an timer instead of `extended_macro` use `delayed_extended` as the section definition.

---
**Defaults**

`extended_macro` comes with many default functions which do not need to be added or declared by the user.
`extended_macro` and `delayed_extended` comes with many default functions which do not need to be added or declared by the user.

---

Expand All @@ -60,46 +59,43 @@ On your Run the following commands in the command prompt of the Raspberry Pi run

```BASH
cd ~
git clone https://github.com/droans/klipper_extras.git
git clone -b shell-install --single-branch git@github.com:droans/klipper_extras.git
```

Next, install Extended Macro using our install script. As with any script, please take time and read the script first so you can ensure the safety. Alternatively, if you understand how, you may download the files and manually install Extended Macro:
Next, install Extended Template using our installation script. As with any script, please take time and read the script first, so you can ensure the safety. Alternatively, if you understand how, you may download the files and manually install Extended Macro:

```BASH
./klipper_extras/install.sh
```

When the script finishes, copy the install script to your home directory so that we can edit it. On Line #3, you will need to adjust `FLAG=1` to `FLAG=0`. The reason for copying the file to your home directory is Moonraker will not like it if you edit the file while it is in the clone repo directory and will force you to overwrite the changes.

```BASH
cp ${HOME}/klipper_extras/install.sh ${HOME}/extended_macro_install.sh
nano /home/pi/extended_macro_install.sh
```

At this point, Extended Macro is ready to be used. If you wish to add this to your update manager, edit your `moonraker.conf` file and add the following:

```BASH
[update_manager extended_macro]
```INI
[update_manager extended_template]
type: git_repo
primary_branch: main
primary_branch: shell-install
path: ~/klipper_extras
origin: https://github.com/droans/klipper_extras.git
env: ~/klippy-env/bin/python
requirements: extended_macro/requirements.txt
install_script: ./../extended_macro_install.sh
install_script: install.sh
is_system_service: False
managed_services: klipper
```

With this above setup pointing the installation script to your home directory, anytime the extended_macro extension gets updated, your extended_macro_install.sh file will not be overwritten by the GitHub clone of the repo.
The script will automatically generate the `requirements.txt` file and (if the use chooses to have moonraker update this extension automatically) `extended_template_update.conf` file.

We want the `FLAG=0` to stay that way. You only need to install the additional software packages one time. Moonraker will take care of ensuring that the packages needed by the extension are updated (the `requirements` option takes care of that for you).
If the user chooses to have moonraker update this extension automatically, then the script will append the following to the end of your `moonraker.conf` file:

```INI
#add extended_template extension to Klipper
[include extended_template_update.conf]
```
---

*Custom Utility Functions*:

`update_gcode_variable(macro_name: str, variable: str, value: Any)`: Update a G-Code variable for any macro. Unlike `SET_GCODE_VARIABLE`, allows for non-literals to be passed and updated.
`update_gcode_variable(macro_name: str, variable: str, value: Any)`: Update a G-Code variable for any macro. Unlike `SET_GCODE_VARIABLE`, allows for non-literals to be passed and updated.

`update_dict(dict: dict, keys: Union[list, tuple, set, str], value: Any)`: Update the value of a dictionary. Allows for a nested value to be updated if a list, tuple, or set is passed for `keys`.

Expand Down
4 changes: 0 additions & 4 deletions extended_macro/requirements.txt

This file was deleted.

Loading

0 comments on commit 62bf23b

Please sign in to comment.