diff --git a/common/kiway.cpp b/common/kiway.cpp
index e6cbbbdce8..d936bfec77 100644
--- a/common/kiway.cpp
+++ b/common/kiway.cpp
@@ -473,9 +473,9 @@ void KIWAY::SetLanguage( int aLanguage )
     }
 }
 
+
 void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
 {
-#if 1
     if( m_ctl & KFCTL_CPP_PROJECT_SUITE )
     {
         // A dynamic_cast could be better, but creates link issues
@@ -486,7 +486,6 @@ void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
         if( top )
             top->CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
     }
-#endif
 
     for( unsigned i=0;  i < KIWAY_PLAYER_COUNT;  ++i )
     {
@@ -498,6 +497,29 @@ void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
 }
 
 
+void KIWAY::ProjectChanged()
+{
+    if( m_ctl & KFCTL_CPP_PROJECT_SUITE )
+    {
+        // A dynamic_cast could be better, but creates link issues
+        // (some basic_frame functions not found) on some platforms,
+        // so a static_cast is used.
+        EDA_BASE_FRAME* top = static_cast<EDA_BASE_FRAME*>( m_top );
+
+        if( top )
+            top->ProjectChanged();
+    }
+
+    for( unsigned i=0;  i < KIWAY_PLAYER_COUNT;  ++i )
+    {
+        KIWAY_PLAYER* frame = GetPlayerFrame( ( FRAME_T )i );
+
+        if( frame )
+            frame->ProjectChanged();
+    }
+}
+
+
 bool KIWAY::ProcessEvent( wxEvent& aEvent )
 {
     KIWAY_EXPRESS* mail = dynamic_cast<KIWAY_EXPRESS*>( &aEvent );
diff --git a/common/settings/settings_manager.cpp b/common/settings/settings_manager.cpp
index 780bfe063d..f6c85075aa 100644
--- a/common/settings/settings_manager.cpp
+++ b/common/settings/settings_manager.cpp
@@ -28,6 +28,7 @@
 #include <confirm.h>
 #include <dialogs/dialog_migrate_settings.h>
 #include <gestfich.h>
+#include <kiway.h>
 #include <macros.h>
 #include <project.h>
 #include <project/project_archiver.h>
@@ -53,6 +54,7 @@ const char* traceSettings = "SETTINGS";
 
 SETTINGS_MANAGER::SETTINGS_MANAGER( bool aHeadless ) :
         m_headless( aHeadless ),
+        m_kiway( nullptr ),
         m_common_settings( nullptr ),
         m_migration_source()
 {
@@ -715,6 +717,9 @@ bool SETTINGS_MANAGER::LoadProject( const wxString& aFullPath, bool aSetActive )
     m_projects[fullPath]->setLocalSettings( settings );
     settings->SetProject( m_projects[fullPath].get() );
 
+    if( m_kiway )
+        m_kiway->ProjectChanged();
+
     return success;
 }
 
@@ -731,6 +736,12 @@ bool SETTINGS_MANAGER::UnloadProject( PROJECT* aProject, bool aSave )
 
     m_projects.erase( aProject->GetProjectFullName() );
 
+    // Remove the reference in the environment to the previous project
+    wxSetEnv( PROJECT_VAR_NAME, "" );
+
+    if( m_kiway )
+        m_kiway->ProjectChanged();
+
     return true;
 }
 
diff --git a/common/single_top.cpp b/common/single_top.cpp
index 3293d13c53..e1e4d7fe16 100644
--- a/common/single_top.cpp
+++ b/common/single_top.cpp
@@ -359,6 +359,8 @@ bool PGM_SINGLE_TOP::OnPgmInit()
         }
     }
 
+    // Tell the settings manager about the current Kiway
+    GetSettingsManager().SetKiway( &Kiway );
 
     // Use KIWAY to create a top window, which registers its existence also.
     // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
diff --git a/include/eda_base_frame.h b/include/eda_base_frame.h
index 8233056491..cc30128951 100644
--- a/include/eda_base_frame.h
+++ b/include/eda_base_frame.h
@@ -496,6 +496,11 @@ public:
      */
     void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override;
 
+    /**
+     * Notification event that the project has changed.
+     */
+    virtual void ProjectChanged() {}
+
     const wxString& GetAboutTitle() const { return m_AboutTitle; }
 
     /**
diff --git a/include/kiway.h b/include/kiway.h
index 57bf52fa60..c26436cbf2 100644
--- a/include/kiway.h
+++ b/include/kiway.h
@@ -382,6 +382,12 @@ public:
      */
     VTBL_ENTRY void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged );
 
+    /**
+     * Calls ProjectChanged() on all KIWAY_PLAYERs.
+     * Used after changing the project to ensure all players are updated correctly.
+     */
+    VTBL_ENTRY void ProjectChanged();
+
     KIWAY( PGM_BASE* aProgram, int aCtlBits, wxFrame* aTop = NULL );
 
     /**
diff --git a/include/settings/settings_manager.h b/include/settings/settings_manager.h
index 0d90956da6..ad4fc5026a 100644
--- a/include/settings/settings_manager.h
+++ b/include/settings/settings_manager.h
@@ -26,6 +26,7 @@
 
 class COLOR_SETTINGS;
 class COMMON_SETTINGS;
+class KIWAY;
 class PROJECT;
 class PROJECT_FILE;
 class REPORTER;
@@ -43,6 +44,13 @@ public:
      */
     bool IsOK() { return m_ok; }
 
+    /**
+     * Associate this setting manager with the given Kiway.
+     *
+     * @param aKiway is the kiway this settings manager should use
+     */
+    void SetKiway( KIWAY* aKiway ) { m_kiway = aKiway; }
+
     /**
      * Takes ownership of the pointer passed in
      * @param aSettings is a settings object to register
@@ -350,6 +358,9 @@ private:
     /// True if running outside a UI context
     bool m_headless;
 
+    /// The kiway this settings manager interacts with
+    KIWAY* m_kiway;
+
     std::vector<std::unique_ptr<JSON_SETTINGS>> m_settings;
 
     std::unordered_map<wxString, COLOR_SETTINGS*> m_color_settings;
diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp
index 37bcaf4d66..e64641b640 100644
--- a/kicad/kicad.cpp
+++ b/kicad/kicad.cpp
@@ -92,6 +92,7 @@ bool PGM_KICAD::OnPgmInit()
 
     m_bm.InitSettings( new KICAD_SETTINGS );
     GetSettingsManager().RegisterSettings( PgmSettings() );
+    GetSettingsManager().SetKiway( &Kiway );
     m_bm.Init();
 
     // Add search paths to feed the PGM_KICAD::SysSearch() function,
diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp
index c6821ccaa7..b32d4d39ec 100644
--- a/pcbnew/pcb_edit_frame.cpp
+++ b/pcbnew/pcb_edit_frame.cpp
@@ -51,6 +51,7 @@
 #include <functional>
 #include <project/project_file.h>
 #include <project/net_settings.h>
+#include <settings/common_settings.h>
 #include <settings/settings_manager.h>
 #include <swig/python_scripting.h>
 #include <tool/tool_manager.h>
@@ -323,6 +324,10 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
 
     InitExitKey();
 
+    // Ensure the Python interpreter is up to date with its environment variables
+    PythonSyncEnvironmentVariables();
+    PythonSyncProjectName();
+
     GetCanvas()->SwitchBackend( m_canvasType );
     ActivateGalCanvas();
 
@@ -1265,6 +1270,27 @@ void PCB_EDIT_FRAME::PythonPluginsShowFolder()
 }
 
 
+void PCB_EDIT_FRAME::PythonSyncEnvironmentVariables()
+{
+#if defined( KICAD_SCRIPTING )
+    COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
+
+    for( auto& var : settings->m_Env.vars )
+        pcbnewUpdatePythonEnvVar( var.first, var.second );
+#endif
+}
+
+
+void PCB_EDIT_FRAME::PythonSyncProjectName()
+{
+#if defined( KICAD_SCRIPTING )
+    wxString evValue;
+    wxGetEnv( PROJECT_VAR_NAME, &evValue );
+    pcbnewUpdatePythonEnvVar( wxString( PROJECT_VAR_NAME ).ToStdString(), evValue );
+#endif
+}
+
+
 void PCB_EDIT_FRAME::InstallFootprintPropertiesDialog( MODULE* Module )
 {
     if( Module == NULL )
@@ -1338,11 +1364,21 @@ void PCB_EDIT_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVars
     if( aTextVarsChanged )
         GetCanvas()->GetView()->UpdateAllItems( KIGFX::ALL );
 
+    // Update the environment variables in the Python interpreter
+    if( aEnvVarsChanged )
+        PythonSyncEnvironmentVariables();
+
     Layout();
     SendSizeEvent();
 }
 
 
+void PCB_EDIT_FRAME::ProjectChanged()
+{
+    PythonSyncProjectName();
+}
+
+
 void PCB_EDIT_FRAME::LockModule( MODULE* aModule, bool aLocked )
 {
     const wxString ModulesMaskSelection = wxT( "*" );
diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h
index f7aa2db494..5d22bd0f5e 100644
--- a/pcbnew/pcb_edit_frame.h
+++ b/pcbnew/pcb_edit_frame.h
@@ -304,6 +304,18 @@ public:
      */
     void PythonPluginsShowFolder();
 
+    /**
+     * Synchronize the environment variables from KiCad's environment into the Python interpreter.
+     * Do nothing if KICAD_SCRIPTING is not defined.
+     */
+    void PythonSyncEnvironmentVariables();
+
+    /**
+     * Synchronize the project name from KiCad's environment into the Python interpreter.
+     * Do nothing if KICAD_SCRIPTING is not defined.
+     */
+    void PythonSyncProjectName();
+
     /**
      * Update the layer manager and other widgets from the board setup
      * (layer and items visibility, colors ...)
@@ -948,6 +960,8 @@ public:
      */
     void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override;
 
+    void ProjectChanged() override;
+
     void SyncToolbars() override;
 
     wxString GetCurrentFileName() const override;
diff --git a/pcbnew/swig/python_scripting.cpp b/pcbnew/swig/python_scripting.cpp
index aef4076e3a..4f53afa1fc 100644
--- a/pcbnew/swig/python_scripting.cpp
+++ b/pcbnew/swig/python_scripting.cpp
@@ -210,7 +210,8 @@ bool pcbnewInitPythonScripting( const char * aUserScriptingPath )
     {
         PyLOCK lock;
 
-        snprintf( cmd, sizeof( cmd ), "import sys, traceback\n"
+        // Load os so that we can modify the environment variables through python
+        snprintf( cmd, sizeof( cmd ), "import sys, os, traceback\n"
                   "sys.path.append(\".\")\n"
                   "import pcbnew\n"
                   "pcbnew.LoadPlugins(\"%s\")", aUserScriptingPath );
@@ -318,6 +319,30 @@ void pcbnewFinishPythonScripting()
 }
 
 
+void pcbnewUpdatePythonEnvVar( const std::string& aVar, const wxString& aValue )
+{
+    char cmd[1024];
+
+    // Ensure the interpreter is initalized before we try to interact with it
+    if( !Py_IsInitialized() )
+        return;
+
+    snprintf( cmd, sizeof( cmd ),
+              "# coding=utf-8\n"      // The values could potentially be UTF8
+              "os.environ[\"%s\"]=\"%s\"\n",
+              aVar.c_str(),
+              TO_UTF8( aValue ) );
+
+    PyLOCK lock;
+
+    int retv = PyRun_SimpleString( cmd );
+
+    if( retv != 0 )
+        wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd );
+}
+
+
+
 #if defined( KICAD_SCRIPTING_WXPYTHON )
 void RedirectStdio()
 {
diff --git a/pcbnew/swig/python_scripting.h b/pcbnew/swig/python_scripting.h
index 369d50c8d4..c577734a30 100644
--- a/pcbnew/swig/python_scripting.h
+++ b/pcbnew/swig/python_scripting.h
@@ -78,6 +78,15 @@ void        pcbnewGetScriptsSearchPaths( wxString& aNames );
  */
 void        pcbnewGetWizardsBackTrace( wxString& aNames );
 
+/**
+ * Set an environment variable in the current Python interpreter.
+ *
+ * @param aVar is the variable to set
+ * @param aValue is the value to give it
+ */
+void        pcbnewUpdatePythonEnvVar( const std::string& aVar, const wxString& aValue );
+
+
 #ifdef KICAD_SCRIPTING_WXPYTHON
 void        RedirectStdio();
 wxWindow*   CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameId );