Python4maXbox Code

Thanks to Python4Delphi we now can evaluate (for expressions) or exec (for statements) some Python code in our scripts. This version 4.7.5.80 July 2021 allows us with the help of a Python Dll and an environment with modules in site-packages execute Py-functions. But the most is only available in a 32-bit space, possible also with 64-bit Python means the call of the external shell (ExecuteShell) with installed Python versions to choose from. By the way also a Python4Lazarus is available.

1413 unit uPSI_PythonEngine.pas _P4D_Beta
1414 unit uPSI_VclPythonGUIInputOutput;
1415 unit uPSI_VarPyth;
1416 unit JclUsesUtils;
1417 unit uPSI_cParameters;
1418 unit uPSI_WDCCMisc; (uPSI_cFileTemplates);
1419 uPSI_WDCCOleVariantEnum.pas
1420 unit uPSI_WDCCWinInet.pas _WDCC
1421 uPSI_PythonVersions.pas _P4D_
1422 unit uPSI_PythonAction.pas _P4D_

Imagine you need a 512bit hash and you don’t have the available function. SHA256 or SHA512 is a secure hash algorithm which creates a fixed length one way string from any input data. OK you start the Python-engine in your maXbox script and load the DLL. Most of the time you don’t need to install Python cause you find a DLL for example in the Wow64 subsystem and load it. WoW64 (Windows 32-bit on Windows 64-bit) is a subsystem of the Windows operating system capable of running 32-bit applications on 64-bit Windows.

To get a Dll that fits your size and space you can check with

writeln('is x64 '+botostr(Isx64('C:\maXbox\EKON24\python37.dll'))); 

Or best you install the environment with: https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe

I provide also just a Dll one which we use most at:

https://sourceforge.net/projects/maxbox/files/Examples/EKON/P4D/python37.dll/download

Search for registered versions is possible with the function GetRegisteredPythonVersions : TPythonVersions’); On 64-bit Windows the 32-bit python27.dll is really in C:\Windows\sysWOW64. But if you try opening the C:\Windows\system32\python27.dll in a 32-bit process, it’ll open just fine. If I’m not mistaken, WOW stands for Woodoo Of Windows. 😉

To make sure your path is the right test it with OpenDll():

 procedure TDynamicDll.LoadDll; begin OpenDll( DllName ); end; eng.dllpath:= 'C:\maXbox\EKON25' eng.dllname:= 'python37.dll'; eng.AutoLoad:= false; try eng.OpenDll('C:\maXbox\EKON25\python37.dll'); 

Or then you type the path and name of the Dll:

 with TPythonEngine.create(self) do begin //Config Dll or Autoload Dllpath:= 'C:\Users\max\AppData\Local\Programs\Python\Python36-32\' Dllname:= 'python37_32.dll'; LoadDll; writeln(pythonhome) writeln(ExecModule) pypara:= 'https://en.wikipedia.org/wiki/WoW64'; //pypara:= filetostring(exepath+'maXbox4.exe') try writeln(evalstr('__import__("math").sqrt(45)')); writeln(evalstr('__import__("hashlib").sha1(b"https://en.wikipedia.org/wiki/WoW64").hexdigest()')); writeln(evalstr('__import__("hashlib").sha1(b"'+pypara+'").hexdigest().upper()')); writeln(evalstr('__import__("hashlib").sha256(b"'+pypara+'").hexdigest().upper()')); writeln(evalstr('__import__("hashlib").sha512(b"'+pypara+'").hexdigest().upper()')); finally free end; end; 

So the last line is the sha512 and the result is: 8B94C64213CAD……and so on. The important thing is the evalstr() function. The eval() allows us to execute arbitrary strings as Python code. It accepts a source string and returns an object. But we can also import modules with the inbuilt syntax ‘import(“hashlib”).

The eval() is not just limited to simple expression. We can execute functions, call methods, reference variables and so on. So we use this by using the __import__() built-in function. Note also that the computed hash is converted to a readable hexadecimal string by hexdigest().upper()’ and uppercase the hex-values in one line, amazing isn’t it.

We step a bit further to exec a script in a script! If we call a file or an const Python command then we use ExecString(PYCMD); The script you can find at: http://www.softwareschule.ch/examples/pydemo.txt

The essence is a bit of script:

 const PYCMD = 'print("this is box")'+LB+ 'import sys'+LB+ 'f=open(r"1050pytest21.txt","w")'+LB+ 'f.write("Hello PyWorld_mX4, \n")'+LB+ 'f.write("This data will be written on the file.")'+LB+ 'f.close()'; 

The LB = CR+LF; is important cause we call it like a file or stream and exec() is cleaning (delete CR) and encoding the passing script afterwards:

 writeln('ExecSynCheck1 '+botostr(eng.CheckExecSyntax(PYCMD))); eng.ExecString(PYCMD); 

We also check the syntax before to prevent an exception: Exception: Access violation at address 6BA3BA66 in module ‘python36.dll’. or ‘python37_32.dll’ Read of address 000000AD. Free the engine means destroying it calls Py_Finalize, which frees all memory allocated by the Python Dll.

Or, if you’re just using the Python API without the VCL wrappers like we do, you can probably just call Py_NewInterpreter on your TPythonInterface object to get a fresh execution environment without necessarily discarding everything done before!

By success of execute PYCMD a file (1050pytest21.txt) is written with some text so we executed line by line the PYCMD.

This is the whole tester Procedure PYLaz_P4D_Demo2; but key takeaway is that only use eval() with a trusted source.

https://thepythonguru.com/python-builtin-functions/eval/

https://github.com/maxkleiner/python4delphi/tree/master/Tutorials

Eval can be evil if untrusted
 Procedure PYLaz_P4D_Demo2; //https://wiki.freepascal.org/Python4Delphi var eng : TPythonEngine; out1: TPythonGUIInputOutput; begin eng:= TPythonEngine.Create(Nil); out1:= TPythonGUIInputOutput.create(nil) out1.output:= pyMemo; //debugout.output; //memo2; out1.RawOutput:= False; out1.UnicodeIO:= False; out1.maxlines:= 20; out1.displaystring('this string thing') //eng.IO:= Out1; Out1.writeline('draw the line'); try eng.LoadDll; eng.IO:= Out1; if eng.IsHandleValid then begin writeln('DLLhandle: '+botostr(eng.IsHandleValid)) WriteLn('evens: '+ eng.EvalStringAsStr('[x**2 for x in range(15)]')); WriteLn('gauss: '+ eng.EvalStringAsStr('sum([x for x in range(101)])')); WriteLn('gauss2: '+ eng.EvalStr('sum([x % 2 for x in range(10100)])')); WriteLn('mathstr: '+ eng.EvalStr('"py " * 7')); WriteLn('builtins: '+ eng.EvalStr('dir(__builtins__)')); WriteLn('upperstr: '+ eng.EvalStr('"hello again".upper()')); WriteLn('workdir: '+ eng.EvalStr('__import__("os").getcwd()')); writeln('syncheck '+ botostr(eng.CheckEvalSyntax('print("powers:",[x**2 for x in range(10)])'))); eng.ExecString('print("powers:",[x**2 for x in range(10)])'); writeln('ExecSynCheck1 '+botostr(eng.CheckExecSyntax(PYCMD))); eng.ExecString(PYCMD); writeln('ExecSynCheck2 '+botostr(eng.CheckExecSyntax(myloadscript))); writeln('ExecSynCheck3 '+ botostr(eng.CheckExecSyntax(filetostring(PYSCRIPT)))); eng.ExecString(filetostring(PYSCRIPT)); writeln(eng.Run_CommandAsString('print("powers:",[x**2 for x in range(10)])',eval_input)); writeln(eng.Run_CommandAsString('sum([x for x in range(201)])',eval_input)); pymemo.update; end else writeln('invalid library handle! '+Getlasterrortext); writeln('PythonOK: '+botostr(PythonOK)); except eng.raiseError; writeln('PyErr '+ExceptionToString(ExceptionType, ExceptionParam)); finally eng.free; end; out1.free; //pyImport(PyModule); end; 

The procedure raiseError helps to find errors for example:

Exception: : SRE module mismatch.
Make sure you do not have any mismatch between Python interpreter version used (like 3.7) and the ‘re’ python module (like 3.6.1).

The resolution of Dlls has changed in Python 3.8 for Windows.

 New in version 3.8: Previous versions of CPython would resolve Dlls using the default behavior for the current process. This led to inconsistencies, such as only sometimes searching PATH or the current working directory, and OS functions such as AddDllDirectory having no effect. 

And here’s the reference output from Procedure PYLaz_P4D_Demo2:

DLLhandle: TRUE
evens: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196]
gauss: 5050
gauss2: 5050
mathstr: py py py py py py py
builtins: ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', 'build_class', 'debug', 'doc', 'import', 'loader', 'name', 'package', 'spec', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
upperstr: HELLO AGAIN
workdir: C:\maXbox\maxbox3\maxbox3\maXbox3
syncheck TRUE
ExecSynCheck1 TRUE
ExecSynCheck2 TRUE
ExecSynCheck3 TRUE
None
20100
PythonOK: TRUE
mX4 executed: 28/07/2021 18:23:31 Runtime: 0:0:1.609 Memload: 43% use

Conclusion: The eval() method parses the expression passed to it and runs python expression(code) (but no statements) within the program. For you and for me 5 functions are crucial:

Function CheckEvalSyntax(const str: AnsiString):Boolean'); Function CheckExecSyntax(const str: AnsiString):Boolean'); Procedure ExecString(const command: AnsiString);'); Procedure ExecString3(const command: AnsiString);');//alias Procedure ExecStrings4(strings: TStrings);'); Function EvalStringAsStr(const command: AnsiString):string');//alias Function EvalStr(const command: AnsiString): string');

Also, consider the situation when you have imported os module in your python program like above WriteLn(‘workdir: ‘+ eng.EvalStr(‘import(“os”).getcwd()’));. The os module provides portable way to use operating system functionalities like: read or write a file. A single command can delete all files in your system!

So eval expects an expression, import is a statement. That said, what you can trying is the following combination:

 Println('exec as eval: '+eng.EvalStr('exec("import os as o")')); Println('exec: '+eng.EvalStr('o.getcwd()')); >>> exec as eval: None >>> exec: C:\maXbox\mX47464\maxbox4 writeln('uuid: '+eng.evalstr('exec("import uuid") or str(uuid.uuid4())')); >>> uuid: 3b2e10f9-0e31-4961-9246-00852fd508bd writeln('wget: '+ eng.EvalStr('__import__("urllib")')); writeln('wget_like: '+ eng.EvalStr('__import__("urllib.request").request.urlretrieve("http://google.com/index.html", filename="index.html")')); 

Compare to inline code

Lets do comparison between inline code and eval?

 import json import urllib.request urlData = "http://api.openweathermap.org/data/2.5/weather?q=Kiruna,SE" webURL = urllib.request.urlopen(urlData) data = webURL.read() JSON_object = json.loads(data.decode('utf-8')) 

We open an API, read it an convert to JSON now the eval:

 execString('import urllib.request'); execString('import json'); Println('openurl: '+eng.EvalStr('json.loads(urllib.request.urlopen("'+ urlData+'").read().decode("utf-8"))')); 

You can use exec in eval instead if you intend to import the module or also ExecString: it depends on the global or local namespace you set, means also the second line knows the import statement from first line:

 eng.ExecString('import math'); Println('evalexec: '+eng.EvalStr('dir(math)')); 

When you use a float that doesn’t have an exact binary float representation, the Decimal constructor cannot create an accurate decimal representation. For example:

 import decimal from decimal import Decimal x = Decimal(0.1) print(x) 

And the same with an EvalExec:

 pymemo.lines.add('Decimal: '+ eng.EvalStr('__import__("decimal").Decimal(0.1)')); >>> 0.1000000000000000055511151231257827021181583404541015625 
Compile the Python Engine to run in maXbox and execute scripts in the code.

Minimal Configuration Py on the fly

The minimal configuration depends on your Python-installation and the UseLastKnownVersion property in TDynamicDll but once known it goes like this with raiseError to get the Python exceptions:

 with TPythonEngine.Create(Nil) do begin pythonhome:= PYHOME; try loadDLL; Println('Decimal: '+ EvalStr('__import__("decimal").Decimal(0.1)')); except raiseError; finally free; end; end; 
Py on the Fly
Model View – Packages and Components of P4D

FRACTRAN is a Turing-complete esoteric programming language invented by the mathematician John Horton Conway.

A FRACTRAN program is an ordered list of positive fractions P = ( f 1 , f 2 , … , f m ) {\displaystyle P=(f_{1},f_{2},\ldots ,f_{m})} , together with an initial positive integer input n {\displaystyle n} .

The program is run by updating the integer n {\displaystyle n} as follows:

  • for the first fraction, f i {\displaystyle f_{i}} , in the list for which n f i {\displaystyle nf_{i}} is an integer, replace n {\displaystyle n} with n f i {\displaystyle nf_{i}}  ;
  • repeat this rule until no fraction in the list produces an integer when multiplied by n {\displaystyle n} , then halt.

Python: Generate series from a fractran program

 const PYFRAC = 'def fractran(n, fstring="17 / 91, 78 / 85, 19 / 51, 23 / 38, 29 / 33,"'+LF+ ' "77 / 29, 95 / 23, 77 / 19, 1 / 17, 11 / 13," '+LF+ ' "13 / 11, 15 / 14, 15 / 2, 55 / 1"): '+LF+ ' flist = [Fraction(f) for f in fstring.replace(" ", "").split(",")]'+LF+ ' '+LF+ ' n = Fraction(n) '+LF+ ' while True: '+LF+ ' yield n.numerator '+LF+ ' for f in flist: '+LF+ ' if (n * f).denominator == 1: '+LF+ ' break '+LF+ ' else: '+LF+ ' break '+LF+ ' n *= f '; 

And then we call the function:

 with TPythonEngine.Create(Nil) do begin pythonhome:= PYHOME; loadDll; try Execstr('from fractions import Fraction'); Execstring(PYFRAC); Execstr('n, m = 2, 15'); println(EvalStr('"First %i members of fractran(%i):\n " % (m, n) +'+ '", ".join(str(f)for f,i in zip(fractran(n),range(m)))')); except raiseError; writeln(ExceptionToString(ExceptionType, ExceptionParam)); finally Free; end; end; 

REgEx in a maXbox script

ttp://www.rosettacode.org/wiki/Fractran#Delphi

 procedure TFractancompile2(prog: string); //m: TMatch; begin with TRegExpr.Create do begin //m := reg.Match(prog); Expression:= '\s*(\d*)\s*\/\s*(\d*)\s*'; //while m.Success do begin if Exec(prog) then Repeat SetLength(num, Length(num) + 1); //num[high(num)] := StrToIntDef(m.Groups[1].Value, 0); num[high(num)]:= StrToIntDef(match[1], 0); SetLength(den, Length(den) + 1); den[high(den)]:= StrToIntDef(match[2], 0); //m := m.NextMatch; Until not ExecNext; Free; end; end; 

First 15 members of Fractran(2):

2, 15, 825, 725, 1925, 2275, 425, 390, 330, 290, 770, 910, 170, 156, 132

Top 3 tricks

  1. more than one statement on one line is possible with a semicolon:
 //17. Ternary operations eg.execString('x=1; y=2'); println('ternary: '+eg.evalStr('1 if x > 0 and y > x else -1 ')); 

2. embrace your path with quotes to make spaces in path valid:

 saveString(exepath+'pyhelp.py', 'help(''print'')'); print(getDosOutput('py "'+exepath+'pyhelp.py"', exePath)); 

3. One-liner with Python -c command

 print(getDosOutput('py -c "import sys; print(sys.version.split()[0])"',exePath)); >>> 3.7.3 print(getDosOutput('py -3.7-32 -c "from rich.console import Console;'+ 'import sys; print(sys.version.split()[0]);'+ 'console = Console();'+ 'print(console);'+ 'console.print(''Hello, [bold]World[/bold]!'');"',exePath)); >>> 3.7.9 >>> <console width=79 None> >>> Hello, World! 

You want to run code snippets without call Python interactive mode. You can execute the code with Python -c option in command line window. Above, it checks the current Python version an delivers the shell result (in this case 3.7.3) back to the maXbox console!

Or direct with a procedure to print out on memo2 as console:

 Proc CaptureConsoleOutput(DosApp :Str;AMemo : TMemo); CaptureConsoleOutput('py -c"import sys;print(sys.version.split()[0])"',memo2); 

This procedure is able to capture the information shown in a command prompt (e.g. cmd window) at a specific command moment and send it to a text or a memo file.

http://www.softwareschule.ch/examples/pydemo38.htm

Try to reduce complexity whenever possible. Let’s take an example. Say you want to figure out how many non-square numbers there are between 1 and 1000. Recall that a non-square number n is just a number that can not be expressed as n = m**2 for some other number m. The following code solves our problem:

 println('design ex1: '+eg.evalstr('len(set(range(1,1001)).difference(set(map(lambda x:x**2, range(1,1001)))))')); 

Although the code above solves the problem (even using cool features like sets and the map function), it looks horrible. It probably took you some time to read it. It is way too complicated. Consider the following simplification:

 eg.execstr('from math import sqrt'); eg.execstr('non_square_numbs = list(range(1, 1001))'); eg.execstr('for n in range(1, int(sqrt(1001))):'+LF+ ' non_square_numbs.remove(n ** 2)'); println('design ex2: '+eg.evalstr('len(non_square_numbs)')); 

The new code is not only clearer but also faster. I only need to run through the numbers up to the square root of 1001. https://towardsdatascience.com/how-to-write-high-quality-python-as-a-data-scientist-cde99f582675

http://www.softwareschule.ch/examples/pydemo40_2.htm

Deep Purple Made in Japan 1972

4. eval() and exec()

Python has the ability to read a string dynamically and treat it as a line of code. The eval() and exec() functions (used to evaluate expressions and execute statements, respectively) are used to do this.

You can also pass dynamically constructed strings to these functions. For example, you can create 1000 variables named x_0, x_1, …, x_999 without manually writing these variable declarations in your code. This may seem like a completely pointless feature, but it’s not.

In the broader context of programming in general, not just Python, the use of eval/exec is incredibly powerful but also a security risk because it allows you to write dynamic code that uses information available at runtime to solve problems which cannot even be expressed at compile time. […] exec is literally a Python interpreter embedded inside Python, so if you have a particularly hard problem to solve, one of the ways you can solve it is to write a program to *write a program to solve it*, then use exec to run that second program.

 Const FUNCA = 'def func(x): '+LF+ ' intermediate_var = x**2 + x + 1 '+LF+ ' if intermediate_var % 2: '+LF+ ' y = intermediate_var **3 '+LF+ ' else: '+LF+ ' y = intermediate_var **3 + 1 '+LF+ ' return y '; eg.Execstring(FUNCA); println('funca expression:'+eg.evalstr('func(3)')); >>> funca expression:2197 
Tests with VSC web and export to maXbox with a lot of trial and errors
Py Extension
modules loaded with mixed code pascal-python

Python REST API Example

Now that the requests module is installed let’s again open up a text editor and enter the following code:

 import requests url = "https://api.apilayer.com/image_to_text/url?url=http%3A%2F%2Fwww.kleiner.ch%2Fkleiner%2Fimages%2Fuml_buch.jpg" payload = {} headers= { "apikey": "DNwCF9Rf6y1AmSSednjn8Zh.............." } response = requests.request("GET", url, headers=headers, data = payload) status_code = response.status_code result = response.text 

Image to Text API uses a neural net (LSTM) based OCR engine which is focused on line recognition, but also supports recognizing the character patterns. It supports both handwriting and printed materials.

https://apilayer.com/marketplace/image_to_text-api?live_demo=show

Now the same code for Python4maXbox:

 procedure PyAPICode(imgpath: string); begin with TPythonEngine.Create(Nil) do begin pythonhome:= 'C:\Users\max\AppData\Local\Programs\Python\Python36-32\'; try loadDLL; ExecString('import requests, json'); ExecStr('url= "https://api.apilayer.com/image_to_text/url?url='+imgpath+'"'); ExecStr('payload = {}'); ExecStr('headers= {"cache-control":"no-cache",'+ '"apikey":"DNwCF9Rf6y1AmSSednjn8Zh........."}'); Println(EvalStr('requests.request("GET",url,headers=headers,data=payload).text')); except raiseError; finally free; end; end; end; 

The API will also work for handwritings. Even for non-English texts. The output is JSON data with all the text extracted and even the language is auto detected,

 http://www.kleiner.ch/kleiner/images/uml_buch.jpg { "all_text": "ih \u00bb Der Entwickler\nFachwissen f\u00fcr Programmierer\nMax Kleiner\nUML\nmit Delphi\nObjektorientiert modellieren\nund entwickeln\nSoftware & Support", "annotations": [ "ih", "\u00bb", "Der", "Entwickler", "Fachwissen", "f\u00fcr", "Programmierer", "Max", "Kleiner", "UML", "mit", "Delphi", "Objektorientiert", "modellieren", "und", "entwickeln", "Software", "&", "Support" ], "lang": "de" } 

Also a compiled snippet from a WinInet class is available.

 function Image_to_text_API2(AURL, url_imgpath, aApikey: string): string; var httpq: THttpConnectionWinInet; rets: TStringStream; heads: TStrings; iht: IHttpConnection2; //losthost:THTTPConnectionLostEvent; begin httpq:= THttpConnectionWinInet.Create(true); rets:= TStringStream.create(''); heads:= TStringlist.create; try heads.add('apikey='+aAPIkey); iht:= httpq.setHeaders(heads); httpq.Get(Format(AURL,[url_imgpath]), rets); if httpq.getresponsecode=200 Then result:= rets.datastring else result:='Failed:'+ itoa(Httpq.getresponsecode)+Httpq.GetResponseHeader('message'); except writeln('EWI_HTTP: '+ExceptiontoString(exceptiontype,exceptionparam)); finally httpq:= Nil; heads.Free; rets.Free; end; end; 

Proxies can be configured too: Pointer to a null-terminated string that specifies the name of the proxy server(s) to use when proxy access is specified by setting dwAccessType to INTERNET_OPEN_TYPE_PROXY. Do not use an empty string, because InternetOpen will use it as the proxy name. The WinINet functions recognize only CERN type proxies (HTTP only) and the TIS FTP gateway (FTP only). If Microsoft Internet Explorer is installed, these functions also support SOCKS proxies. FTP requests can be made through a CERN type proxy either by changing them to an HTTP request or by using InternetOpenUrl. If dwAccessType is not set to INTERNET_OPEN_TYPE_PROXY, this parameter is ignored and should be NULL. For more information about listing proxy servers, see the Listing Proxy Servers section of Enabling Internet Functionality.

One liner print shell

When you have to print out a graphi in ASCII style or some diagrams two things are important:

First you have to set a fixed font in your shell or form.

On a more casual note, fixed fonts can also help multi-line emoticons appear correctly, which is not always the case with a proportional font. See the example below:

A bicycle emoticon in the “Times” font: ~  __0
 _-\<,_
(*)/ (*)

The same bicycle emoticon in the “Courier” font: ~  __0
 _-\<,_
(*) / (*)

Second you have to replace a python \n as newline in a corresponding CRLF :

mem.text:=StringReplace(evalStr('"n".join(["".join([(love[(x-y)%len(love)] if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3<=0 else" ")for x in range(-30,30 )])for y in range(15,-15,-1)])'),'n', CRLF,[rfReplaceAll, rfIgnoreCase]); 
 procedure PYdemo32; var frm: TForm; mem: TMemo; begin with TPythonEngine.Create(Nil) do begin pythonhome:= 'C:\Users\breitsch\AppData\Local\Programs\Python\Python37-32\'; try loadDLL; execStr('love="ILovemaXbox"'); frm:= TForm.create(self); mem:= TMemo.Create(frm); mem.parent:= frm; mem.color:= clblack; mem.font.name:= 'Courier'; //a fixed font size. mem.font.size:= 12; mem.font.color:= clred; mem.Align:= alClient; with frm do begin position:= poScreenCenter; caption:= 'PyHeart2'; width:= 600; height:= 500; //canvas.brush.bitmap mem.text:=StringReplace(evalStr('"n".join(["".join([(love[(x-y)%len(love)] if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3<=0 else" ")for x in range(-30,30 )])for y in range(15,-15,-1)])'),'n', CRLF,[rfReplaceAll, rfIgnoreCase]); Showmodal; end; except raiseError; finally free; frm.Free; end; end; end; 

So, if you ever want to create an text-based image that takes up more than one line, using a fixed font can make sure it will appear correctly.

output from form to shell

Installing py modules in a 32-bit environment

You need to use pip.exe that’s in the Scripts folder of the 32-bit version of Python (.\Programs\Python\Python36-32\). Or you can run pip as a module using:

C:\maXbox\works2021\maxbox4>py -3.6-32 -m pip install pendulum

Collecting pendulum
Using cached pendulum-2.1.2.tar.gz (81 kB)
Installing build dependencies … done
Getting requirements to build wheel … done
Preparing metadata (pyproject.toml) … done
Collecting pytzdata>=2020.1
Downloading pytzdata-2020.1-py2.py3-none-any.whl (489 kB)
|████████████████████████████████| 489 kB 2.2 MB/s
Requirement already satisfied: python-dateutil<3.0,>=2.6 in c:\users\max\appdata
\local\programs\python\python36-32\lib\site-packages (from pendulum) (2.8.2)
Requirement already satisfied: six>=1.5 in c:\users\max\appdata\local\programs\p
ython\python36-32\lib\site-packages (from python-dateutil<3.0,>=2.6->pendulum) (
1.16.0)
Building wheels for collected packages: pendulum
Building wheel for pendulum (pyproject.toml) … done
Created wheel for pendulum: filename=pendulum-2.1.2-cp36-cp36m-win32.whl size=
118491 sha256=a95530585cd0627f76365c5765e7d240c0aeaa126d3ac0313f7dd27e2b51447c
Stored in directory: c:\users\max\appdata\local\pip\cache\wheels\c7\33\5b\9bd2
31ee982125a3e4eaa5c77a04de43eba25ee940cfb5a84a
Successfully built pendulum
Installing collected packages: pytzdata, pendulum
Successfully installed pendulum-2.1.2 pytzdata-2020.1

Tips for one liners

 //Tip 1: Using List Comprehensions for Concise Iteration println('squared_numbers '+evalStr('[x ** 2 for x in range(10)]')); //Tip 2: Using Dictionaries for Efficient Data Retrieval println('user_info '+ evalStr('{"username": "john_doe", "age": 30, "email": "john@example.com"}')); //Tip 3: Unpacking and Multiple Assignments in One Line execStr('x, y = 10, 20; x, y = y, x # Swap values'); println('multiple assigns swap: '+evalStr('x, y')); //Tip 4: Python Generators execStr(FiboG); //execStr('fibonacci_generator()'); println('gen return: '+evalStr('list(fibonacci_generator())')); //Tip 5: Context Managers for Resource Management execStr('with open(r"data.txt", "r") as file:'+LF+ ' content = file.read()'); println('open return: '+evalStr('content')); //Tip 8: Built-in Functions You Shouldn’t Ignore println('map squared_numbers: '+ evalStr('list(map(lambda x: x ** 2, [1, 2, 3, 4, 5]))')); //Tip 9: Optimizing Loops with the “enumerate()” Function execStr('fruits = ["apple", "banana", "cherry", "sharks"]; l=[]'); execStr('for index, fruit in enumerate(fruits):'+LF+ ' l.append(f"Idx: {index}, Fruit: {fruit}")'); println('enumerate return: '+evalStr('l')); >> map squared_numbers: [1, 4, 9, 16, 25] >> enumerate return: ['Idx: 0, Fruit: apple', 'Idx: 1, Fruit: banana', 'Idx: 2, Fruit: cherry', 'Idx: 3, Fruit: sharks'] 
in maXbox5 beta

C:\Program Files\Streaming\IBZ2021\Module2_3\EKON27>py -3.12 -m pip install qrcode
Collecting qrcode
Using cached qrcode-7.4.2-py3-none-any.whl (46 kB)
Collecting typing-extensions (from qrcode)
Obtaining dependency information for typing-extensions from https://files.pythonhosted.org/packages/b7/f4/6a90020cd2d93349b442bfcb657d0dc91eee65491600b2cb1d388bc98e6b/typing_extensions-4.9.0-py3-none-any.whl.metadata
Downloading typing_extensions-4.9.0-py3-none-any.whl.metadata (3.0 kB)
Collecting pypng (from qrcode)
Using cached pypng-0.20220715.0-py3-none-any.whl (58 kB)
Collecting colorama (from qrcode)
Using cached colorama-0.4.6-py2.py3-none-any.whl (25 kB)
Downloading typing_extensions-4.9.0-py3-none-any.whl (32 kB)
Installing collected packages: pypng, typing-extensions, colorama, qrcode
WARNING: The script qr.exe is installed in ‘C:\Users\breitsch\AppData\Local\Programs\Python\Python312\Scripts’ which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use –no-warn-script-location.
Successfully installed colorama-0.4.6 pypng-0.20220715.0 qrcode-7.4.2 typing-extensions-4.9.0

[notice] A new release of pip is available: 23.2.1 -> 23.3.2
[notice] To update, run: C:\Users\breitsch\AppData\Local\Programs\Python\Python312\python.exe -m pip install –upgrade pip

Python 3.12.x 64 bit in maXbox5.1

Normally it shuts down after one run, so you have to set autofinalize:= false

 with TPythonEngine.Create(Nil) do begin //pythonhome:= PYHOME64; optional //opendll(PYDLL64) loadDLL; autofinalize:= false; try 
matplotlib 3.9.0

28 thoughts on “Python4maXbox Code

  1. function CleanString(const s : AnsiString; AppendLF : Boolean) : AnsiString;
    var
    i : Integer;
    begin
    result := s;
    if s = ” then
    Exit;
    i := Pos(AnsiString(CR),s);
    while i > 0 do
    begin
    Delete( result, i, 1 );
    i := PosEx(AnsiString(CR),result, i); //fix
    end;
    if AppendLF and (result[length(result)] LF) then
    Result := Result + LF;
    end;

    Like

    1. >>> mystr
      ‘hello world, how do i enter line breaks?’
      >>> mystr.replace(‘ ‘, ”)
      ‘helloworld,howdoienterlinebreaks?’

      In the example above, I replaced all spaces. The string ‘\n’ represents newlines. And \r represents carriage returns (if you’re on windows, you might be getting these and a second replace will handle them for you!).
      basically:

      # you probably want to use a space ‘ ‘ to replace `\n`
      mystring = mystring.replace(‘\n’, ‘ ‘).replace(‘\r’, ”)

      Note also, that it is a bad idea to call your variable string, as this shadows the module string. Another name I’d avoid but would love to use sometimes: file. For the same reason a semantic syntax checker.

      Like

      1. Create a string containing line breaks
        Newline code \n(LF), \r\n(CR + LF)
        Triple quote ”’ or “””
        With indent
        Concatenate a list of strings on new lines
        Split a string into a list by line breaks: splitlines()
        Remove or replace line breaks
        Output with print() without a trailing newline

        Like

    1. writeln(‘wget: ‘+ eng.EvalStr(‘__import__(“urllib”)’));
      writeln(‘wget_like: ‘+ eng.EvalStr(‘__import__(“urllib.request”).request.urlretrieve(“http://google.com/index.html”, filename=”indexg.html”)’));

      Like

      1. If you get the error: Exception: : DLL load failed: %1 is not a valid Win32 application.
        Solution set the pythonhome to 32bit:
        PYHOME = ‘C:\Users\max\AppData\Local\Programs\Python\Python36-32\’;
        eng.pythonhome:= PYHOME;
        >>>wget:

        Like

  2. Install from within script, e.g. numpy:

    eng.ExecString(‘import subprocess’);
    eng.ExecString(‘subprocess.call([“pip”, “install”, “numpy”])’)
    eng.ExecString(‘import numpy’);

    Like

    1. Complete Scenario in maXbox:
      1. install SymPy
      eng.ExecString(‘import subprocess’);
      eng.ExecString(‘subprocess.call([“pip”, “install”, “sympy”])’)
      2. compute solver
      avar:= ‘-2’;
      eng.ExecString(‘x=Symbol(“x”)’);
      eng.ExecString(‘x,y=symbols(“x y”)’);
      writeln(eng.EvalStr(‘solveset(Eq(x**2-9,0), x)’));
      writeln(eng.EvalStr(‘solveset(Eq(x**2-3*x,’+avar+’),x)’));
      writeln(eng.EvalStr(‘solveset(exp(x),x)’));
      println(eng.EvalStr(‘linsolve([Eq(x-y,4),Eq( x + y ,1) ], (x, y))’));
      3. check results:
      FiniteSet(-3, 3)
      FiniteSet(1, 2)
      EmptySet
      FiniteSet((5/2, -3/2))

      https://www.tutorialspoint.com/sympy/sympy_solvers.htm

      Like

      1. Another 4 liner:
        eng.ExecString(‘import subprocess’);
        eng.ExecString(‘subprocess.call([“pip”, “install”, “langdetect”])’)
        eng.ExecString(‘from langdetect import detect’);
        println(‘detect: ‘+eng.EvalStr(‘detect(“bonjour mes ordinateurs”)’));
        >>> detect: fr

        Like

  3. Great, be sure that Pyhome and Pydll are of the same filespace when installing a package:
    const
    PYHOME = ‘C:\Users\max\AppData\Local\Programs\Python\Python36-32\’;
    PYDLL = ‘C:\Users\max\AppData\Local\Programs\Python\Python36-32\python36.dll’;
    eng.pythonhome:= PYHOME;
    eng.opendll(PYDLL);

    Like

    1. Possible to get the types:
      eng.ExecString(‘import decimal’)
      //https://www.w3schools.com/python/python_ref_functions.asp
      writeln(‘is instance: ‘+eng.EvalStr(‘isinstance(decimal.Decimal,’+
      ‘(float, int, str, list, dict, tuple, type))’));
      writeln(‘is type: ‘+eng.EvalStr(‘type(str(decimal.Decimal(0.1)))’));
      writeln(‘is type: ‘+eng.EvalStr(‘type(float(decimal.Decimal(0.1)))’));
      writeln(‘is type: ‘+eng.EvalStr(‘type(decimal.Decimal)’));
      writeln(‘is type: ‘+eng.EvalStr(‘type(decimal)’));
      >>> is instance: True
      is type:
      is type:
      is type:
      is type:

      Like

  4. Question was to check types in an eval, example with array and list:

    execstring(‘from array import *’);
    execstring(‘students=[“Alex”,”Bill”,”Max”,”Andy”,”Molly”,”Rose”]’);
    println(‘array(“i”, [45,34,167])’);
    //// Now this function tolist() converts the array into a list.
    execstring(‘a = array(“i”, [45,34,167]).tolist()’);
    print(evalstr(‘type(a)’));
    print(evalstr(‘a’));
    print(evalstr(‘array(“i”, [45,34,167]).tolist()’));
    execstring(‘print(a)’);
    execstring(‘print(” this to memo2 ? “)’);
    print(evalstr(‘print(” this to memo2 ?”)’));
    println(evalstr(‘str(” this to memo2 ?”)’));
    //print(evalstr(‘a’));
    //Here’s an example of a slice in Python:
    println(evalstr(‘students[3:5]’));

    >>> array(“i”, [45,34,167])
    //[45, 34, 167][45, 34, 167]None
    this to memo2 ?
    [‘Andy’, ‘Molly’]

    Like

  5. To call a function with return:
    Const FUNC = ‘def say_hi():’+LF+
    ‘ return “Hello there from maXbox4″‘;

    eng.Execstring(FUNC)
    print(eng.EvalStr(‘say_hi()’));

    Note that in Python GUI by Python4maXbox, to print the result, you just need to state the inbuilt print() or println or writeln function, it’s not enough just by return statement. The output is rerouted to memo2 component in maXbox by print or write.

    Like

    1. Using a return inside of a loop will break it and exit the function even if the iteration is still not finished.
      Instead of that, you can use a different approach:
      Yielding your data:
      execstr(‘list = [(“Alice”,25),(“Bob”,30),(“Jake”,27),(“Barbara”,40)]’);
      execstr(‘def multituple(): ‘+LF+
      ‘ for name, age in list: ‘+LF+
      ‘ yield (name,”is aged”,str(age))’);
      println(EvalStr(‘tuple(multituple())’));
      >>>((‘Alice’, ‘is aged’, ’25’), (‘Bob’, ‘is aged’, ’30’), (‘Jake’, ‘is aged’, ’27’), (‘Barbara’, ‘is aged’, ’40’))

      Like

  6. to print out with format:
    print(getDosOutput(‘py -3.7-32 -c “import pprint; from faker import Faker;’+
    ‘ fake = Faker();’+
    ‘([pprint.pprint(fake.profile()) for n in range(3)])’,exePath));
    or inline:
    writeln(eng.evalstr(‘str([fake.profile() for n in range(3)]).replace(“},”,”\r\n”)’));

    Like

  7. get a list of all p4d methods (vcl4python):
    print(‘dir p4d:: ‘+getDosOutput(‘py -3.6-32 -c “from delphivcl import *; ‘+
    ‘print(dir()[0:45])”‘,exePath));

    Liked by 1 person

    1. the result of 45 slice: dir p4d:: [‘Abort’, ‘Action’, ‘ActionList’, ‘ActivityIndicator’, ‘Application’, ‘BaseBindScopeComponent’, ‘BaseLinkingBindSource’, ‘BaseObjectBindSource’, ‘BasicAction’, ‘BasicBindComponent’, ‘Bevel’, ‘BindComponentDelegate’, ‘BindingsList’, ‘BitBtn’, ‘Bitmap’, ‘BoundLabel’, ‘Button’, ‘Canvas’, ‘CheckBox’, ‘Collection’, ‘ColorBox’, ‘ComboBox’, ‘Component’, ‘ContainedAction’, ‘ContainedActionList’, ‘ContainedBindComponent’, ‘Control’, ‘ControlBar’, ‘CreateComponent’, ‘CustomAction’, ‘CustomActionList’, ‘CustomActivityIndicator’, ‘CustomBindingsList’, ‘CustomControl’, ‘CustomDrawGrid’, ‘CustomEdit’, ‘CustomForm’, ‘CustomGrid’, ‘CustomLinkControlToField’, ‘CustomLinkListControlToField’, ‘CustomLinkPropertyToField’, ‘CustomMemo’, ‘CustomNumberBox’, ‘CustomPrototypeBindSource’, ‘CustomStyleServices’]

      Like

      1. Combine python shell with python4maxbox script:
        with TPythonEngine.Create(Nil) do begin
        pythonhome:= ‘C:\users\breitsch\AppData\Local\Programs\Python\Python37-32\’;
        try
        //loadDLL;
        opendll(PYDLL32)
        Println(‘Decimal: ‘+
        EvalStr(‘__import__(“decimal”).Decimal(0.1)’));
        println(evalstr(‘sum([i for i in range(101)])’));
        //execstr(filetostring(exepath+’EKON26\gini_split.py’));
        execstr(filetostring(‘C:\Program Files\Streaming\IBZ2021\Module2_3\EKON26\gini_split.py’));
        println(evalstr(‘gini_index([[[1,1], [1,0]], [[1,1], [1,0]]], [0,1])’));
        except
        raiseError;
        finally
        free;
        end;
        end;

        Like

  8. Cracking consciousness
    If these guys are correct, the ramifications are huge. Not only would it resolve, in a snap, a conundrum that’s troubled mankind for millennia — it would also pave the way for an entirely new episode in human history: minds uploaded to computers and all.
    This isn’t surprising. It’s been three hundred years now since Gottfried Leibniz made the fundamental and obvious point that, if you could inflate a human brain to the size of a large building and step inside, you still wouldn’t be able to ‘locate’ within it any subjective perceptions.

    https://www.spectator.co.uk/article/cracking-consciousness-how-do-our-minds-really-work-

    Like

    1. that mental function exists somehow outside of or separate from the biological functioning of the brain’ only shows that mice need certain bits of their brains to be functioning properly if they are to solve puzzles. Oh.

      Like

  9. IP Tracker:
    eng.ExecString(‘import os’+LF+’import json’+LF+’import urllib.request’);
    eng.ExecString(‘url = “http://ip-api.com/json/”‘);
    eng.ExecString(‘targetip = “129.42.38.1”‘);
    eng.ExecString(‘response=urllib.request.urlopen(url+targetip)’);
    //writeln(eng.EvalStr(‘response.read()’));
    eng.ExecString(‘data=response.read()’);
    eng.ExecString(‘values=json.loads(data)’);
    println(eng.EvalStr(‘”ISP: “+values[“isp”]’));
    println(eng.EvalStr(‘”city: “+values[“city”]’));
    println(eng.EvalStr(‘”IP: “+values[“query”]’));

    Like

  10. procedure getAscPrimesPython(ftopic: string);
    45 begin
    46 with TPythonEngine.Create(Nil) do begin
    47 pythonhome:= PYHOME;
    48 loadDLL();
    49 try
    50 //Execstring(‘import urllib.request, json, requests’);
    51 execStr(‘from sympy import isprime’);
    52 execStr(‘def ascending(x=0):’+LF+
    53 ‘ for y in range(x*10 + (x%10)+1, x*10+10):’+LF+
    54 ‘ yield from ascending(y)’+LF+
    55 ‘ yield(y)’);
    56 Println(EvalStr(‘sorted(x for x in ascending() if isprime(x))’));
    57 Print(‘sum of ascprimes: ‘+
    58 EvalStr(‘sum(sorted(x for x in ascending() if isprime(x)))’));
    59 except
    60 raiseError;
    61 finally
    62 unloadDll;
    63 Free;
    64 end;
    65 end;
    66 end;

    Like

Leave a comment