Readme creator update to match latest releases. Component parts of Readme

This commit is contained in:
MikeTheWatchGuy 2019-09-08 10:54:13 -04:00
parent 7c723133e0
commit 385c2020f0
10 changed files with 13669 additions and 384 deletions

View File

@ -28,19 +28,25 @@ HOW DO I INSERT IMAGES ???
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png)
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) tkinter
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) tkinter 2.7
[![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) Qt
[![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) WxPython
[![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) Web (Remi)
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-4.2.0-red.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-4.4.0-red.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-2.2.0-blue.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-2.4.0-blue.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_Version-0.26.0-orange.svg?longCache=true&style=for-the-badge)
@ -119,11 +125,15 @@ HOW DO I INSERT IMAGES ???
#### Quick Links To Help and Read Up on the Latest News and Releases
[ReadTheDocs](http://www.PySimpleGUI.org) <------ THE best place to read the docs due to TOC, all docs in 1 place, and better formatting. START here in your education.
### START HERE - User Manual with Table of Contents
[Homepage - Lastest Readme and Code - GitHub](http://www.PySimpleGUI.com)
[ReadTheDocs](http://www.PySimpleGUI.org) <------ THE best place to read the docs due to TOC, all docs in 1 place, and better formatting. START here in your education. Easy to remember PySimpleGUI.org.
#### Quick Links To Help and The Latest News and Releases
[Homepage - Lastest Readme and Code - GitHub](http://www.PySimpleGUI.com) Easy to remember: PySimpleGUI.com
[Announcements of Latest Developments, Release news, Misc](https://github.com/PySimpleGUI/PySimpleGUI/issues/142)
@ -211,15 +221,15 @@ PySimpleGUI runs on Windows, Linux and Mac, just like tkinter, Qt, WxPython and
* Windows 7, 8, 10
* Linux on PC - Tested on **many** distributions
* Linux on Raspbnerry Pi
* Linux on Android - Must use either Termux or PyDroid3
* Mac OS (Sorry I don't know much about Macs)
* Linux on Android - Can use either Termux or PyDroid3
* Mac OS (Sorry don't know much about Macs other than Macs don't like tkinter)
#### Python versions
As of 9/25/2018 **both Python 3 and Python 2.7 are supported** when using **tkinter version** of PySimpleGUI! The Python 3 version is named `PySimpleGUI`. The Python 2.7 version is `PySimpleGUI27`. They are installed separately and the imports are different. See instructions in Installation section for more info. **None** of the other ports can use Python 2.
Note that the 2.7 port will cease to exist on this GitHub on Jan 1, 2020. If you would like to know how much time you have to move over to the Python 3 version of PySimpleGUI, then go here: https://pythonclock.org/. The only thing that will be available is an unsupported PyPI release of PySimpleGUI27.
Note that the 2.7 port will *cease to exist on this GitHub* on Jan 1, 2020. If you would like to know how much time you have to move over to the Python 3 version of PySimpleGUI, then go here: https://pythonclock.org/. The only thing that will be available is an unsupported PyPI release of PySimpleGUI27.
By "will cease to exist on this GitHub" I mean, it will be deleted entirely. No source code, no supporting programs. Nothing. If you're stuck using 2.7 in December, it would behoove you to fork the 2.7 code on Dec 31, 2019. Legacy Python doesn't have a permanent home here.
@ -949,6 +959,7 @@ Features of PySimpleGUI include:
- Movable windows
- Animated GIFs
- No async programming required (no callbacks to worry about)
- Built-in debugger and REPL
- User expandable by accessing underlying GUI Framework widgets directly
---
@ -986,7 +997,7 @@ The Single Line Progress Meter is a good example. It requires one and only 1 lin
Be Pythonic...
This one is difficult for me to define. The code implementing PySimpleGUI isn't PEP8 compliant, but it is consistent. The important thing was what the user saw and experienced while coding, NOT the choices for naming conventions in the implementation code.
This one is difficult for me to define. The code implementing PySimpleGUI isn't PEP8 compliant, but it is consistent. The important thing was what the user saw and experienced while coding, NOT the choices for naming conventions in the implementation code. The user interface to PySimpleGUI now has a PEP8 compliant interface. The methods are snake_case now (in addition to retaining the older CamelCase names)
I ended up defining it as - attempt to use language constructs in a natural way and to exploit some of Python's interesting features. It's Python's lists and optional parameters make PySimpleGUI work smoothly.
@ -1001,9 +1012,11 @@ Here are some Python-friendly aspects to PySimpleGUI:
#### Lofty Goals
> Change Python
> Teach GUI Programming to Beginners
The hope is **not** that ***this*** package will become part of the Python Standard Library. The hope is that Python will become ***the*** go-to language for creating GUI programs that run on Windows, Mac, and Linux *for all levels of developer*. Perhaps this sort of package is needed to make that happen. It would be nice if there was a "unified interface" for GUIs like PySimpleGUI presents, along with the vendor specific calls.
By and large PySimpleGUI is a "pattern based" SDK. Complete beginners can copy these standard design patterns or demo programs and modify them without necessarily understanding all of the nuts and bolts of what's happening. For example, they can modify a layout by adding elements even though they may not yet grasp the list of lists concept of layouts.
Beginners certainly can add more `if event == 'my button':` statements to the event loop that they copied from the same design pattern. They will not have to write classes to use this package.
> Capture Budding Graphic Designers & Non-Programmers
@ -1131,12 +1144,13 @@ When you type sg, Python will tell you the full patch to your PySimpleGUI file /
### Finding Out Where Your PySimpleGUI Is Coming From (from within your code)
If you continue to have troubles with getting the right version of PySimpleGUI loaded, THE ***definitive*** way to determine where your program is getting PySimpleGUI from is to add a print to your program. It's that *simple*!
If you continue to have troubles with getting the right version of PySimpleGUI loaded, THE ***definitive*** way to determine where your program is getting PySimpleGUI from is to add a print to your program. It's that *simple*! You can also get the version you are running by also printing
```python
import PySimpleGUI as sg
print(sg)
print(sg.version)
```
Just like when using the REPL >>> to determine the location, this `print` in your code will display the same path information.
@ -1149,6 +1163,7 @@ If you're not connected to the net on your target machine, or pip isn't working,
Be ***sure*** that you delete this PySimpleGUI.py file if you install a newer pip version. Often the sequence of events is that a bug you've reported was fixed and checked into GitHub. You download the PySimpleGUI.py file (or the appropriately named one for your port) and put with your app. Then later your fix is posted with a new release on PyPI. You'll want to delete the GitHub one before you install from pip.
### Prerequisites
Python 2.7 or Python 3
tkinter
@ -1214,12 +1229,11 @@ Then use either "high level" API calls or build your own windows.
Yes, it's just that easy to have a window appear on the screen using Python. With PySimpleGUI, making a custom window appear isn't much more difficult. The goal is to get you running on your GUI within ***minutes***, not hours nor days.
***WARNING*** Do NOT use PySimpleGUI with Python 3.7.4. tkiter is having issues with that release. Things like Table colors stopped working entirely.
***WARNING*** Do NOT use PySimpleGUI with Python 3.7.3 and 3.7.4. tkiter is having issues with that release. Things like Table colors stopped working entirely. None of us want to debug tkinter code. It's difficult enough debugging your code and PySimpleGUI code. A lot of time has already been spent debugging this one so no need for you to suffer too.
### Python 3.7
It puzzles me why a beginner would install 3.7. Or even a seasoned programmer. What specific feature of 3.7 are you using that is not in 3.6? If you are unable to answer this, then ***you should be running 3.6***, an immensely solid release of Python. If you must run 3.7, try 3.7.2 instead. It does work with PySimpleGUI with no known issues.
It puzzles me why a beginner would install 3.7. Or even a seasoned programmer. What specific feature of 3.7 are you using that is not in 3.6? If you are unable to answer this, then ***it's strongly suggested that you run 3.6***, an immensely solid release of Python with all those goodie inside like f-strings. If you must run 3.7, try 3.7.2 instead. It does work with PySimpleGUI with no known issues.
## Using - Python 2.7
@ -1246,6 +1260,7 @@ else:
This will automatically import the correct library based on the Python version number reported by the Python interpreter.
NOTE: It's 2019 and 2.7 support is being systematically removed. This construct will be removed from the demo programs shortly. 2.7 users can still run these demos, but they will need to change the import from PySimpleGUI to PySimpleGUI27. It save 4 lines of code and an import from sys in the process.
---

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,9 @@ There are too many to list!!
There are over 170 sample programs to give you a jump start.
These programs are an integral part of the overall PySimpleGUI documentation and learning system. They will give you a headstart in a way you can learn from and understand. They also show you integration techiques to other packages that have been figured out for you.
You will find Demo Programs located in a subfolder named "Demo Programs" under each of the PySimpleGUI ports on GitHub.
You will find Demo Programs located in a subfolder named "Demo Programs" under the top level and each of the PySimpleGUI ports on GitHub.
Demo programs for plain PySimpleGUI (tkinter)
https://github.com/PySimpleGUI/PySimpleGUI/tree/master/DemoPrograms
@ -37,6 +38,12 @@ There are not many programs under each of the port's folders because the main De
* [Mido](https://github.com/olemb/mido)
* [Matplotlib](https://matplotlib.org/)
* [PyMuPDF](https://github.com/rk700/PyMuPDF)
* OpenCV
* pymunk
* psutil
* pygame
* Forecastio
# Creating a Windows .EXE File
@ -99,34 +106,56 @@ For a fun time, add these lines to the top of your script
```
This will turn all of your print statements into prints that display in a window on your screen rather than to the terminal.
# Look and Feel (`ChangleLookAndFeel`)
# Look and Feel
You can change defaults and colors of a large number of things in PySimpleGUI quite easily.
## `ChangleLookAndFeel`
Want a quick way of making your windows look a LOT better? Try calling `ChangeLookAndFeel`. It will, in a single call, set various color values to widgets, background, text, etc.
Or dial in the look and feel (and a whole lot more) that you like with the `SetOptions` function. You can change all of the defaults in one function call. One line of code to customize the entire GUI.
While you can define colors for each individual element and you can even define some on a windows wide basis, but it requires setting a lot of different settings.
Dial in the look and feel that you like with the `SetOptions` function. You can change all of the defaults in one function call. One line of code to customize the entire GUI.
Or beginning in version 2.9 you can choose from a look and feel using pre-defined color schemes. Call ChangeLookAndFeel with a description string.
```python
sg.ChangeLookAndFeel('GreenTan')
```
Valid values for the description string are:
Valid look and feel values are currently:
```python
SystemDefault
Reddit
Topanga
GreenTan
Dark
LightGreen
Dark2
Black
Tan
TanBlue
DarkTanBlue
DarkAmber
DarkBlue
Reds
Green
BluePurple
Purple
BlueMono
GreenMono
BrownBlue
BrightColors
NeutralBlue
Kayak
SandyBeach
TealMono
```
GreenTan
LightGreen
BluePurple
Purple
BlueMono
GreenMono
BrownBlue
BrightColors
NeutralBlue
Kayak
SandyBeach
TealMono
The way this call actually works is that it calls `SetOptions` with a LOT of color settings. Here is the actual call that's made. As you can see lots of stuff is defined for you.
```python
SetOptions(background_color=colors['BACKGROUND'],
text_element_background_color=colors['BACKGROUND'],
@ -151,10 +180,12 @@ SetOptions(background_color=colors['BACKGROUND'],
<!-- <+func.ChangeLookAndFeel+> -->
To see the latest list of color choices, take a look at the bottom of the `PySimpleGUI.py` file where you'll find the `ChangLookAndFeel` function.
To see the latest list of color choices you can call `ListOfLookAndFeelValues()`
You can also combine the `ChangeLookAndFeel` function with the `SetOptions` function to quickly modify one of the canned color schemes. Maybe you like the colors but was more depth to your bezels. You can dial in exactly what you want.
**ObjToString**
Ever wanted to easily display an objects contents easily? Use ObjToString to get a nicely formatted recursive walk of your objects.
This statement:
@ -179,16 +210,39 @@ You'll quickly wonder how you ever coded without it.
---
# Known Issues
Well, there are a few quirks, and problems of course. Check the [GitHub Issues database](https://github.com/PySimpleGUI/PySimpleGUI/issues) for a list of them.
As previously mentioned this is also where you should post all problems and enhancements.
## MACS + tkinter = SUCKS
Not sure why, but for over a year and a half, setting the color of buttons does not work on Macs. There have been numerous other problems. Checking the Issues database is the best place to see what they are. If there was a magic wand it would have been used long ago to fix these problems, but there does not appear to be a magic fix.
This was already mentioned at the top of this document but want to make sure it's covered as a "known issue"
## Multiple threads
While not an "issue" this is a ***stern warning***
## **Do not attempt** to call `PySimpleGUI` from multiple threads! It's `tkinter` based and `tkinter` has issues with multiple threads
**Progress Meters** - the visual graphic portion of the meter may be off. May return to the native tkinter progress meter solution in the future. Right now a "custom" progress meter is used. On the bright side, the statistics shown are extremely accurate and can tell you something about the performance of your code. If you are running 2 or more progress meters at the same time using `OneLineProgressMeter`, you need to close the meter by using the "Cancel" button rather than the X
Tkinter also wants to be the MAIN thread in your code. So, if you have to run multiple threads, make sure the GUI is the main thread.
**Async windows** - these include the 'easy' windows (`OneLineProgressMeter` and EasyPrint/Print). If you start overlapping having Async windows open with normal windows then things get a littler squirrelly. Still tracking down the issues and am making it more solid every day possible. You'll know there's an issue when you see blank window.
Other than that, feel free to use threads with PySimpleGUI on all of the ports. You'll find a good example for how to run "long running tasks" in your event loop by looking at the demo program: `Demo_Multithreaded_Long_Tasks.py`
**EasyPrint** - EasyPrint is a new feature that's pretty awesome. You print and the output goes to a window, with a scroll bar, that you can copy and paste from. Being a new feature, it's got some potential problems. There are known interaction problems with other GUI windows. For example, closing a Print window can also close other windows you have open. For now, don't close your debug print window until other windows are closed too.
## Contributing
# Contributing
Core code pull requests are not being accepted at this time.
## Core Code
***Core code changes/pull requests are not being accepted at this time.***
## Demos
You're welcome to share a PySimpleGUI program you've written that you think fits the model of a PySimpleGUI Demo Program.
## GitHub Repos
If you've created a GitHub for your project that uses PySimpleGUI then please submit it to be included in this document or on the PySimpleGUI GitHub site. Also, you'll find a lot more people will look at your code, explore your repo if you have posted **screen shots in your readme**. People *love* success stories and showing your GUI's screen shows you've been successful. Everyone wins!

View File

@ -707,7 +707,7 @@ Long time coming. Docstrings continue to be a focus.
* Fix for debugger trying to execute a REPL comand. The exec is only avilable in Python 3
* main() will display the version number in big letters when program is running
### 4.2 PySimpleGUI 2.2 for PySimpleGUI27 8 - Aug 2019
### 4.2 PySimpleGUI 2.2 for PySimpleGUI27 18 - Aug 2019
The cool lookup release! No more need for FindElement. You can continue to use FindElement.
However, your code will look weird and ancient. ;-) (i.e. readable)
@ -735,6 +735,74 @@ MORE Docstring and main doc updates!
* Fixed sizing Columns! NOW they will finally be the size specified
* Fixed not using the initialdir paramter in PopupGetFile if the no_window option is set
## 4.3 PySimpleGUI Release 22-Aug-2019
PEP8 PEP8 PEP8
Layout controls! Can finally center stuff
Some rather impactful changes this time
Let's hope it doesn't all blow up in our faces!
* PEP8 interfaces added for Class methods & functions
* Finally a PEP8 compliant interface for PySimpleGUI!!
* The "old CamelCase" are still in place and will be for quite some time
* Can mix and match at will if you want, but suggest picking one and sticking with it
* All docs and demo programs will need to be changed
* Internally saving parent row frame for layout checks
* Warnings on all Update calls - checks if Window.Read or Window.Finalize has been called
* Warning if a layout is attempted to be used twice
* Shows an "Error Popup" to get the user's attention for sure
* Removed all element-specific SetFocus methods and made it available to ALL elements
* Listbox - no_scrollbar parameter added. If True then no scrollbar will be shown
* NEW finalize bool parameter added to Window. Removes need to "chain" .Finalize() call.
* NEW element_justification parameter for Column, Frame, Tab Elements and Window
* Valid values are 'left', 'right', 'center'. Only first letter checked so can use 'l', 'c','r'
* Default = 'left'
* Result is that all Elements INSIDE of this container will be justified as specified
* Works well with new Sizer Elements
* NEW justification parameter for Column elements.
* Justifies Column AND the row it's on to this setting (left, right, center)
* Enables individual rows to be justified in addition to the entire window
* NEW Sizer Element
* Has width and height parameters. Can set one or both
* Causes the element it is contained within to expand according to width and height of Sizer Element
* Helps greatly with centering. Frames will shrink to fit the contents for example. Use Sizer to pad out to right size
* Added Window.visibility_changed to match the PySimpleGUIQt call
* Fixed Debugger so that popout window shows any newly added locals
## 4.4 PySimpleGUI Release 5-Sep-2019
* window() - "Calling" your Window object will perform a Read call
* InputText - move cursor to end following Update
* Shortcuts - trying to get a manageable and stable set of Normal, Short, Super-short
* DD - DropDown (Combo)
* LB, LBox - Listbox
* R, Rad - Radio
* ML, MLine - Multiline
* BMenu - ButtonMenu
* PBar, Prog - ProgressBar
* Col - Column
* Listbox - new method GetIndexes returns currently selected items as a list of indexes
* Output - new method Get returns the contents of the output element
* Button - For Macs don't don't allow setting button color. Previously only warned
* ButtonMenu - new Click method will click the button just like a normal Button's Click method
* Column scrolling finally works correctly with mousewheel. Shift+Mouse Scroll will scroll horizontally
* Table - Get method is a dummy version a Get because Qt port got a real Get method
* Table - Will add numerical column headers if Column Headsing is set to None when creating Table Element
* Table - FIXED the columns crazily resizing themselves bug!!
* Table - Can resize individual columns now
* Tree - was not returning Keys but instead the string representation of the key
* SetIcon will set to default base64 icon if there's an error loading icon
* Fix for duplicate key error. Was attempting to add a "unique key counter" onto end of keys if duplicate, but needed to turn into string first
* Columns
* No longer expand nor fill
* Sizing works for both scrolled and normal
* Setting focus - fixed bug when have tabs, columns, frames that have elements that can get the focus. Setting focus on top-level window
* InputText elements will now cause rows to expand due to X direction expansion
* Frame - Trying to set the size but doesn't seem to be setting it correctly
* Tabs will now expand & fill now (I hope this is OK!!!)
### Upcoming
Make suggestions people! Future release features
@ -785,7 +853,7 @@ The PySimpleGUI Organization
This documentation as well as all PySimpleGUI code is Copyright 2018, 2019 by PySimpleGUI.org
PySimpleGUI@PySimpleGUI.org
Send correspondance to PySimpleGUI@PySimpleGUI.com
## License

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
import inspect
import PySimpleGUIlib as sg
import PySimpleGUI as sg
psg_members = inspect.getmembers(sg)
psg_members = inspect.getmembers(PySimpleGUI)
psg_funcs = [o for o in psg_members if inspect.isfunction(o[1])]
psg_classes = [o for o in psg_members if inspect.isclass(o[1])]

View File

@ -1,4 +1,4 @@
from inspect import getmembers, isfunction, isclass, getsource, signature, _empty
from inspect import getmembers, isfunction, isclass, getsource, signature, _empty, isdatadescriptor
from datetime import datetime
import PySimpleGUIlib
import click
@ -6,6 +6,17 @@ import logging
import json
import re
import os
########################################################
# _ _ _ #
# | | | | | | #
# | |_ ___ _ __ ___ _ __ | | __ _| |_ ___ ___ #
# | __/ _ \ '_ ` _ \| '_ \| |/ _` | __/ _ \/ __| #
# | || __/ | | | | | |_) | | (_| | || __/\__ \ #
# \__\___|_| |_| |_| .__/|_|\__,_|\__\___||___/ #
# | | #
# |_| #
########################################################
TAB_char = ' '
TABLE_TEMPLATE='''
Parameter Descriptions:
@ -18,7 +29,18 @@ TABLE_TEMPLATE='''
'''
TABLE_ROW_TEMPLATE = '|{name}|{desc}|'
TABLE_RETURN_TEMPLATE = '|||\n| **return** | {return_guy} |'
TABLE_Only_table_RETURN_TEMPLATE = '''|Name|Meaning|\n|---|---|\n| **return** | $ |'''
TABLE_Only_table_RETURN_TEMPLATE = '''|Name|Meaning|\n|---|---|\n| **return** | $ |''' # $ - is the part for return value
##############################################################################
# _ _ #
# | | | | #
# ___ _ _ ___| |_ ___ _ __ ___ ___| | __ _ ___ ___ ___ ___ #
# / __| | | / __| __/ _ \| '_ ` _ \ / __| |/ _` / __/ __|/ _ \/ __| #
# | (__| |_| \__ \ || (_) | | | | | | | (__| | (_| \__ \__ \ __/\__ \ #
# \___|\__,_|___/\__\___/|_| |_| |_| \___|_|\__,_|___/___/\___||___/ #
# #
# #
##############################################################################
from collections import namedtuple
special_case = namedtuple('special_case', 'ok sig table just_text'.split(' '))
@ -67,7 +89,7 @@ CLASS
}
"""
def get_params_part(code: str) -> dict:
def get_params_part(code: str, versbose=True) -> dict:
"""
Find ":param " part in given "doc string".
@ -80,16 +102,15 @@ def get_params_part(code: str) -> dict:
code = code.strip()
# if doc_string is empty
if code == None: return {}
elif '' == code.strip(): return {}
elif ':param' not in code: return {}
if code == None or code == '' or ':param' not in code:
return {}
elif ':return' in code: # strip ':return:'
new_code = code[:code.index(':return:')]
regg_ = re.compile(r':return[\d\D]*?:param', flags=re.MULTILINE)
if len(list(regg_.finditer(new_code))) > 0:
if versbose:
print(f'warning-> ":return" MUST BY AT THE END. FIX IT NOW in {name_}!!!\nBut i will try to parse it...')
print(f'warning-> ":return" MUST BY AT THE END. FIX IT NOW in "{code}"!!!\nBut i will try to parse it...')
code = re.sub(regg_, r':param', code)
else:
code = new_code
@ -97,20 +118,17 @@ def get_params_part(code: str) -> dict:
try:
only_params = code[code.index(':param'):] # get_only_params_string(code)
except Exception as e:
if versbose: print(f'SORRY, fail at parsing that stuff in {name_}')
if versbose:
print(f'SORRY, fail at parsing that stuff in "{code}"')
return {}
# making dict
param_lines = only_params.split(':param ')
param_lines = [re.sub(r'[ ]{2,}', ' ', i.strip(' ').strip('\t').replace('\n', ' '), flags=re.MULTILINE)
for i in param_lines if i.strip()] # filter empty lines
args_kwargs_pairs = {}
for index, i in enumerate(param_lines):
for i in param_lines:
cols = i.split(':')
param_name, els = cols[0], '\n'.join(
@ -130,137 +148,177 @@ def get_return_part(code: str, line_break=None) -> str:
if ':return:' not in code:
return ''
return code[code.index(':return:')+len(':return:'):].strip().replace('\n', line_break)
def special_cases(function_name, sig, doc_string, line_break=None):
def special_cases(function_name, function_obj, sig, doc_string, line_break=None):
doca, params_names = doc_string.strip(), list(dict(sig).keys())
if 'self' in params_names and len(params_names) == 1 and not doca:
"""
def Get(self):
''' '''
only_self = 'self' in params_names and len(params_names) == 1
->
```python
Get()
```
"""
return special_case(ok=True, just_text=f'\n\n```python\n{function_name}()\n```\n\n', sig='', table='')
############################################################################
# _ _ #
# | | | | #
# ___| | __ _ ___ ___ _ __ _ __ ___ _ __ ___ _ __| |_ _ _ #
# / __| |/ _` / __/ __| | '_ \| '__/ _ \| '_ \ / _ \ '__| __| | | | #
# | (__| | (_| \__ \__ \ | |_) | | | (_) | |_) | __/ | | |_| |_| | #
# \___|_|\__,_|___/___/ | .__/|_| \___/| .__/ \___|_| \__|\__, | #
# | | | | __/ | #
# |_| |_| |___/ #
############################################################################
"""
# TEMPLATE1
# -return -param
elif 'self' in params_names and len(params_names) == 1 and doca and ':param' not in doca and ':return:' not in doca:
"""
def Get(self):
'''
''' '''
# TEMPLATE2 -return -param
def Get(self):
'''
blah blah blah
'''
->
```python
Get() # blah blah blah
```
"""
return special_case(ok=True, just_text=f'\n\n{doca}\n\n```python\n{function_name}()\n```\n\n', sig='', table='')
# +return -param
elif 'self' in params_names and len(params_names) == 1 and doca and ':param' not in doca and ':return:' in doca:
"""
# TEMPLATE3 +return -param
def Get(self):
'''
blah blah blah
:return: blah-blah
'''
"""
if is_propery(function_obj):
# TEMPLATE1
if only_self and not doca:
return special_case(ok=True, just_text=f'\n\n#### property: {function_name}\n\n', sig='', table='')
# TEMPLATE2
elif only_self and doca and ':param' not in doca and ':return:' not in doca:
return special_case(ok=True, just_text=f'\n\n#### property: {function_name}\n{get_doc_desc(doca, function_obj)}\n\n', sig='', table='')
# TEMPLATE3
elif only_self and doca and ':param' not in doca and ':return:' in doca:
return_part, desc = get_return_part(doca, line_break=line_break), get_doc_desc(doca, function_obj)
return special_case(ok=True, just_text='',
sig=f'\n\n#### property: {function_name}\n{desc}\n\n',
table=TABLE_Only_table_RETURN_TEMPLATE.replace('$', return_part) + '\n\n')
->
################################################################################################################
# _ _ _ _ _ #
# | | | | | | | | | | #
# _ __ ___ _ __ _ __ ___ __ _| | ___| | __ _ ___ ___ _ __ ___ ___| |_| |__ ___ __| |___ #
# | '_ \ / _ \| '__| '_ ` _ \ / _` | | / __| |/ _` / __/ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __| #
# | | | | (_) | | | | | | | | (_| | | | (__| | (_| \__ \__ \ | | | | | | __/ |_| | | | (_) | (_| \__ \ #
# |_| |_|\___/|_| |_| |_| |_|\__,_|_| \___|_|\__,_|___/___/ |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/ #
# #
# #
################################################################################################################
```python
Get()
```
"""
# TEMPLATE1
*table*
"""
return_part, desc = get_return_part(doca, line_break=line_break), get_doc_desc(doca)
return special_case(ok=True, just_text='',
sig=f'\n\n{desc}\n\n`{function_name}()`\n\n',
table=TABLE_Only_table_RETURN_TEMPLATE.replace('$', return_part) + '\n\n')
# +return -param
elif 'self' in params_names and len(params_names) == 1 and doca and ':param' not in doca and ':return:' in doca:
"""
def Get(self):
''' '''
# TEMPLATE2 -return -param
def Get(self):
'''
blah blah blah
'''
# TEMPLATE3 +return -param
def Get(self):
'''
blah blah blah
:return: blah-blah
'''
# TEMPLATE4 -return +param
def SetFocus(self, elem):
'''
blah blah blah
:param elem: qwerty
'''
"""
"""
# TEMPLATE1
if only_self and not doca:
return special_case(ok=True, just_text=f'\n\n```python\n{function_name}()\n```\n\n', sig='', table='')
# TEMPLATE2
elif only_self and doca and ':param' not in doca and ':return:' not in doca:
return special_case(ok=True, just_text=f'\n\n{doca}\n\n```python\n{function_name}()\n```\n\n', sig='', table='')
# TEMPLATE3
elif only_self and doca and ':param' not in doca and ':return:' in doca:
return_part, desc = get_return_part(doca, line_break=line_break), get_doc_desc(doca, function_obj)
return special_case(ok=True, just_text='', sig=f'\n\n{desc}\n\n`{function_name}()`\n\n',
table=TABLE_Only_table_RETURN_TEMPLATE.replace('$', return_part) + '\n\n')
# TEMPLATE4
elif only_self and doca and ':param' not in doca and ':return:' in doca:
return special_case(ok=False, just_text='', sig='', table='')
return special_case(ok=False, just_text='', sig='', table='')
def get_doc_desc(doc_string):
def get_doc_desc(doc, original_obj):
if ':param' in doc_string: doc_string = doc_string[:doc_string.index(':param')]
if ':return:' in doc_string: doc_string = doc_string[:doc_string.index(':return:')]
if ':param' in doc_string: doc_string = doc_string[:doc_string.index(':param')]
if ':return:' in doc_string: doc_string = doc_string[:doc_string.index(':return:')]
return_in = ':return' in doc
param_in = ':param' in doc
if return_in and param_in and doc.index(':return') < doc.index(':param'):
logging.error(f'BS. You need to FIX IT. PROBLEM ":return:" BEFORE ":param:" in "{original_obj.__name__}"')
desc = doc_string.strip().replace(' ', '')
if ':param' in doc: doc = doc[:doc.index(':param')]
if ':return' in doc: doc = doc[:doc.index(':return:')]
if ':param' in doc: doc = doc[:doc.index(':param')]
if ':return' in doc: doc = doc[:doc.index(':return:')]
desc = doc.strip().replace(' ', '')
return f'\n{desc}' if desc else ''
def is_propery(func):
return isdatadescriptor(func) and not isfunction(func)
def get_sig_table_parts(function_obj, function_name, doc_string, logger=None, is_method=False, line_break=None, insert_md_section_for__class_methods=False):
"""
Convert "function + __doc__" tp "method call + params table" in MARKDOWN
"""
""" Convert "function + __doc__" tp "method call + params table" in MARKDOWN """
doc_string = doc_string.strip()
# qpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqp
# 0 0 Making INIT_CALL 0 0 #
# qpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqpqp
try:
sig, rows = signature(function_obj).parameters, []
rows = []
sig = {'self': None} if is_propery(function_obj) else signature(function_obj).parameters
except Exception as e:
if logger: logger.error(f'PROBLEM WITH "{function_obj}" "{function_name}":\nit\'s signature is BS. Ok, I will just return \'\' for \'signature\' and \'param_table\'\nOR BETTER - delete it from the 2_readme.md.\n======')
return '', ''
for index, key in enumerate(sig):
val = sig[key].default
if 'self' == str(key):
continue
if val == _empty: rows.append(key)
elif val == None: rows.append(f'{key}=None')
elif type(val) is int: rows.append(f'{key}={val}')
elif type(val) is str: rows.append(f'{key}="{val}"')
elif type(val) is tuple: rows.append(f'{key}={val}')
elif type(val) is bool: rows.append(f'{key}={val}')
else:
raise Exception(f'IDK this type -> {key, val}')
if not is_propery(function_obj):
for key in sig:
val = sig[key].default
if 'self' == str(key):
continue
if val == _empty: rows.append(key)
elif val == None: rows.append(f'{key}=None')
elif type(val) is int: rows.append(f'{key}={val}')
elif type(val) is str: rows.append(f'{key}="{val}"')
elif type(val) is tuple: rows.append(f'{key}={val}')
elif type(val) is bool: rows.append(f'{key}={val}')
else:
raise Exception(f'IDK this type -> {key, val}')
sig_content = f',\n{TAB_char}'.join(rows) if len(rows) > 2 else f', '.join(rows)
sig_content = f',\n{TAB_char}'.join(rows) if len(rows) > 2 else f', '.join(rows) if rows else ''
# # # make 2 line signature into 1-line
# # # sig_content = f',\n{TAB_char}'.join(rows)
# # # if sig_content.count('\n') < 3: sig_content = re.sub(r'\n[ \t]{,8}', ' ', sig_content, flags=re.MULTILINE)
sign = "\n\n{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string), function_name, sig_content)
sign = "\n\n{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string, function_obj), function_name, sig_content)
if is_method:
if insert_md_section_for__class_methods:
sign = "#### {1}\n\n{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string), function_name, sig_content)
# sign = "#### {1}\n\n{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string, function_obj), function_name, sig_content)
sign = "\n\n{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string, function_obj), function_name, sig_content)
else:
sign = "{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string), function_name, sig_content)
sign = "{0}\n\n```\n{1}({2})\n```".format(get_doc_desc(doc_string, function_obj), function_name, sig_content)
# --------------
# SPECIAL CASES
# --------------
result = special_cases(function_name, sig, doc_string, line_break=line_break)
result = special_cases(function_name, function_obj, sig, doc_string, line_break=line_break)
if result.ok:
if result.just_text:
return result.just_text, ''
@ -308,6 +366,13 @@ def pad_n(text): return f'\n{text}\n'
def render(injection, logger=None, line_break=None, insert_md_section_for__class_methods=False):
try:
if 'skip readme' in injection['function_object'].__doc__:
return ''
except Exception as e:
return ''
if injection['part1'] == 'func': # function
sig, table = get_sig_table_parts(function_obj=injection['function_object'],
function_name=injection['part2'],
@ -336,8 +401,7 @@ def readfile(fname):
return ff.read()
def main(do_full_readme=False, files_to_include: list = [], logger=None, output_name=None, delete_html_comments=True, delete_x3_newlines=True, allow_multiple_tags=True, line_break=None, insert_md_section_for__class_methods=True, remove_repeated_sections_classmethods=False):
def main(do_full_readme=False, files_to_include: list = [], logger:object=None, output_name:str=None, delete_html_comments:bool=True, delete_x3_newlines:bool=True, allow_multiple_tags:bool=True, line_break:str=None, insert_md_section_for__class_methods:bool=True, remove_repeated_sections_classmethods:bool=False, output_repeated_tags:bool=False, skip_dunder_method:bool=True):
"""
Goal is:
1) load 1_.md 2_.md 3_.md 4_.md
@ -347,63 +411,84 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
5) replaces classes, functions.
6) join 1 big readme file
:param do_full_readme: if False - use only 2_readme.md
:param files_to_include: list of markdown files to include in output markdown
:param logger: logger object from logging module
:param delete_html_comments: flag for preprocessing input markwon text e.g. deleting every html tag, that is injection_point
:param allow_multiple_tags: flag for replacing every tag in "input markdown text"
:param delete_x3_newlines: flag for deleting '\\n\\n\\n' in final output makrdown text
:param output_name: base filename of output markdown file
:param line_break: linebreak_character in "return part"
:param do_full_readme: (bool=True) if False - use only 2_readme.md
:param files_to_include: (list=[]) list of markdown files to include in output markdown
:param logger: (object=None) logger object from logging module
:param output_name: (str=None) base filename of output markdown file
:param delete_html_comments: (bool=True) flag for preprocessing input markwon text e.g. deleting every html tag, that is injection_point
:param delete_x3_newlines: (bool=True) flag for deleting '\\n\\n\\n' in final output makrdown text
:param allow_multiple_tags: (bool=True) flag for replacing every tag in "input markdown text"
:param line_break: (str=None) linebreak_character in "return part"
:param insert_md_section_for__class_methods: (bool=True) insert '###' sign to class_methods when outputing in markdown
:param remove_repeated_sections_classmethods: (bool=True)
:param output_repeated_tags: (bool=True) log REPEATED tags in file
:param skip_dunder_method: (bool=True) skip __something__ methods in classes
"""
if logger: logger.info(f'STARTING')
# 888888888888888888888888888888888888888888
# =========== 1 loading files =========== #
# 888888888888888888888888888888888888888888
HEADER_top_part = readfile('1_HEADER_top_part.md') # 1
readme = readfile('2_readme.md') # 2
FOOTER = readfile('3_FOOTER.md') # 3
Release_notes = readfile('4_Release_notes.md') # 4
readme = readfile('2_readme.md')
# 8888888888888888888888888888888888888888888888888888888888888888888888888
# =========== 2 GET classes, funcions, varialbe a.k.a. memes =========== #
# 8888888888888888888888888888888888888888888888888888888888888888888888888
psg_members = getmembers(PySimpleGUIlib)
psg_members = getmembers(PySimpleGUIlib) # variables, functions, classes
psg_funcs = [o for o in psg_members if isfunction(o[1])]
psg_classes = [o for o in psg_members if isclass(o[1])]
psg_classes_ = list(set([i[1] for i in psg_classes])) # filtering
psg_funcs = [o for o in psg_members if isfunction(o[1])] # only functions
psg_classes = [o for o in psg_members if isclass(o[1])] # only classes
psg_classes_ = list(set([i[1] for i in psg_classes])) # boildown B,Btn,Butt -into-> Button
psg_classes = list(zip([i.__name__ for i in psg_classes_], psg_classes_))
# IlilIlilIlilIlilIlilIlilIlilIlilIlilIlIlIl
# ilIli- | | -ilIli
# ilIli- _ __ ___ ___ __ _| |_ -ilIli
# ilIli- | '_ ` _ \ / _ \/ _` | __| -ilIli
# ilIli- | | | | | | __/ (_| | |_ -ilIli
# ilIli- |_| |_| |_|\___|\__,_|\__| -ilIli
# 8888888888888888888888888888888888888888888888888888888
# =========== 3 find all tags in 2_readme =========== #
# 8888888888888888888888888888888888888888888888888888888
# PLAN:
# (1) REMOVE HEADER
# strip top of the file head
# (2) find good tags e.g. <!-- <+func.PopupScrolled+> -->
# (3) (optional) find '_' tags e.g.
# '_' tag - is a tag, that has '_' after '.'
#
# Example: <!-- <+func._PopupScrolled+> -->
# /\
# |---that's sign of a bad tags
# (4) (optional) log repeated tags.
# like <!-- <+class.B+> -->
# and
# <!-- <+class.Button+> -->
# 8888888888888888888888888888888888888888888888888888888
# >1 REMOVE HEADER
started_mark = '<!-- Start from here -->'
if started_mark in readme:
readme = readme[readme.index(started_mark)+len(started_mark):]
# find with regex
regex_pattern = re.compile(r'<!-- <\+[a-zA-Z_]+[\d\w_]*\.([a-zA-Z_]+[\d\w_]*)\+> -->')
mark_points = [i for i in readme.split('\n') if regex_pattern.match(i)]
# 2> find good tags
re_tags = re.compile(r'<!-- <\+[a-zA-Z_]+[\d\w_]*\.([a-zA-Z_]+[\d\w_]*)\+> -->')
mark_points = [i for i in readme.split('\n') if re_tags.match(i)]
special_dunder_methods = ['init', 'repr', 'str', 'next']
# 3> find '_' tags OPTION
if skip_dunder_method:
re_bad_tags = re.compile(r'<!-- <\+[a-zA-Z_]+[\d\w_]*\.([_]+[\d\w_]*)\+> -->')
for i in readme.split('\n'):
if re_bad_tags.match(i.strip()):
if not [s_tag for s_tag in special_dunder_methods if s_tag in i.strip()]:
readme = readme.replace(i, '\n')
# if there are REPEATED tags -> show them.
# if not allow_multiple_tags and len(list(set(mark_points))) != len(mark_points):
# [mark_points.remove(x) for x in set(mark_points)]
# if logger:
# logger.error("You have repeated tags! \n {0}".format(
# ','.join(mark_points)))
# return ''
# 4> log repeated tags
if output_repeated_tags:
if not allow_multiple_tags and len(list(set(mark_points))) != len(mark_points):
mark_points_copy = mark_points[:]
[mark_points_copy.remove(x) for x in set(mark_points)]
if logger:
logger.error("You have repeated tags! \n {0}".format(
','.join(mark_points_copy)))
return ''
# 8888888888888888888888888888888888888888888888888888888888888
# =========== 4 structure tags and REAL objects =========== #
@ -417,9 +502,7 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
for tag in func_tags:
try:
__, function_name = tag.split('.')
function_name = function_name.split('+')[0]
part2 = function_name
function_name = part2 = tag.split('.')[1].split('+')[0]
# {{{{{{{{{ filter number }}}}}}}}}
number = ''
@ -430,10 +513,12 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
founded_function = [func for func_name,
func in psg_funcs if func_name == function_name]
if not founded_function:
if logger: logger.error(f'function "{function_name}" not found in PySimpleGUI')
if logger:
logger.error(f'function "{function_name}" not found in PySimpleGUI')
continue
if len(founded_function) > 1:
if logger: logger.error(f'more than 1 function named "{function_name}" found in PySimpleGUI')
if logger:
logger.error(f'more than 1 function named "{function_name}" found in PySimpleGUI')
continue
# {{{{{{{{{ collect }}}}}}}}}
@ -447,15 +532,14 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
})
except Exception as e:
if logger:
logger.error(f' {str(e)}')
logger.error(f' General error in parsing function tag: tag = "{tag}"; error="{str(e)}"')
continue
# 0===0 classes 0===0
for tag in classes_method_tags:
try:
class_name, method_name = tag.split('.')
class_name, method_name = class_name.split('+')[-1], method_name.split('+')[0]
part1, part2 = class_name, method_name
class_name, method_name = part1, part2 = class_name.split('+')[-1], method_name.split('+')[0]
# {{{{{{{{{ filter number }}}}}}}}}
number = ''
@ -463,34 +547,29 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
number, method_name = part2[0], part2[1:]
# {{{{{{{{{ find class }}}}}}}}}
founded_class = [a_class_obj for a_class_name,
a_class_obj in psg_classes if a_class_name == class_name]
founded_class = [a_class_obj
for a_class_name, a_class_obj in psg_classes
if a_class_name == class_name]
if not founded_class:
if logger: logger.error(f'class "{tag}" not found in PySimpleGUI')
if logger: logger.error(f'skipping tag "{tag}", WHY: not found in PySimpleGUI')
continue
if len(founded_class) > 1:
if logger: logger.error(f'more than 1 class named "{tag}" found in PySimpleGUI')
if logger: logger.error(f'skipping tag "{tag}", WHY: found more than 1 class in PySimpleGUI')
continue
# {{{{{{{{{ find method }}}}}}}}}
try:
if method_name != 'doc':
founded_method = getattr(founded_class[0], method_name)
# GLG.append([founded_method, founded_class[0], method_name])
# string_type = str(type(founded_method))
# if 'property' in string_type or 'bound' in string_type:
# print(string_type)
# # import pdb; pdb.set_trace();
# if logger:
# logger.error(f'Property "{founded_method}" is not parsed.')
# continue
else:
founded_method = None
except AttributeError as e:
if logger: logger.error(f'METHOD not found!: {str(e)}')
if logger:
logger.error(f'METHOD not found!: {str(e)}')
continue
except Exception as e:
if logger: logger.error(str(e))
if logger:
logger.error(f'Error in finding the METHOD: {str(e)}')
continue
# {{{{{{{{{ collect }}}}}}}}}
@ -504,66 +583,86 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
})
except Exception as e:
if logger:
logger.error(f'```````````````````````{str(e)}')
logger.error(f' General error in parsing class_method tag: tag = "{tag}"; error="{str(e)}"')
continue
# 888888888888888888888888888888888888888
# =========== 5 injecting =========== #
# 888888888888888888888888888888888888888
# PLAN:
# (1) replace tags in 2_readme
# with properly formateed text
# (2) log some data
# 8888888888888888888888888888888888888888888888888888888
# 1> log some data
success_tags = []
bad_tags = []
for injection in injection_points:
if injection['part2'] == 'doc': # our special snowflake "doc"
# SPECIAL CASE: X.doc tag
if injection['part2'] == 'doc':
readme = readme.replace(injection['tag'], injection['parent_class'].__doc__)
else:
tag = injection['tag']
content = render(injection, logger=logger, line_break=line_break, insert_md_section_for__class_methods=insert_md_section_for__class_methods,)
content = render(injection, logger=logger, line_break=line_break,
insert_md_section_for__class_methods=insert_md_section_for__class_methods,)
tag = injection["tag"]
if content:
success_tags.append(f'{tag} - COMPLETE')
else:
bad_tags.append(f'{tag} - FAIL')
readme = readme.replace(injection['tag'], content)
readme = readme.replace(tag, content)
# 2> log some data
if logger:
success_tags_str = '\n'.join(success_tags).strip()
bad_tags_str = '\n'.join(bad_tags).strip()
# good message
good_message = f'DONE {len(success_tags)} TAGS:\n' + '\n'.join(success_tags) if success_tags_str else 'All tags are wrong//'
# bad message
bad_message = f'FAIL WITH {len(bad_tags)} TAGS:\n' + '\n'.join(bad_tags) if bad_tags_str else 'No bad tags, YES!'
logger.info(good_message)
logger.info(bad_message)
# 8888888888888888888888888888888888
# =========== 6 join =========== #
# 8888888888888888888888888888888888
files = []
if 0 in files_to_include: files.append(HEADER_top_part)
if 0 in files_to_include: files.append(readfile('1_HEADER_top_part.md'))
if 1 in files_to_include: files.append(readme)
if 2 in files_to_include: files.append(FOOTER)
if 3 in files_to_include: files.append(Release_notes)
if 2 in files_to_include: files.append(readfile('3_FOOTER.md'))
if 3 in files_to_include: files.append(readfile('4_Release_notes.md'))
Joined_MARKDOWN = '\n\n'.join(files) if do_full_readme or files else readme
if output_name:
with open(output_name, 'w', encoding='utf-8') as ff:
curr_dt = datetime.today().strftime('<!-- CREATED: %Y-%m-%d %H.%M.%S -->\n')
content = curr_dt + Joined_MARKDOWN
CURR_DT = datetime.today().strftime('<!-- CREATED: %Y-%m-%d %H.%M.%S -->\n')
content = CURR_DT + Joined_MARKDOWN
# {{{{{{{{{ html removing }}}}}}}}}
if delete_html_comments:
if logger: logger.info('Deleting html comments')
if logger:
logger.info('Deleting html comments')
# remove html comments
filt_readme = re.sub(
r'<!--([\s\S]*?)-->', '\n', content, flags=re.MULTILINE)
filt_readme = re.sub(r'<!--([\s\S]*?)-->', '\n', content, flags=re.MULTILINE)
for i in range(5):
filt_readme = filt_readme.replace('\n\n\n', '\n\n')
# add staked_edit
if '<!--stackedit_data:' in content:
stackedit_data = content[content.index(
'<!--stackedit_data:'):]
filt_readme += stackedit_data
stackedit_text = content[content.index('<!--stackedit_data:'):]
filt_readme += stackedit_text
content = filt_readme
@ -573,12 +672,10 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
# removing spaces
content = re.sub(r'^[ ]+$', '', content, flags=re.MULTILINE)
# removing \n
content = re.sub(r'\n{3,}', '\n\n',
content, flags=re.MULTILINE)
content = re.sub(r'\n{3,}', '\n\n', content, flags=re.MULTILINE)
# {{{{{{{{{ remove repeated sections classmethods }}}}}}}}}
if remove_repeated_sections_classmethods:
rega = re.compile(r'((\#+\s\w+)\n\s){2}', flags=re.MULTILINE)
for index, i in enumerate(re.finditer(rega, content)):
print(f'{index} - > {i.group(0)}')
@ -587,14 +684,16 @@ def main(do_full_readme=False, files_to_include: list = [], logger=None, output_
# re
# content = re.sub(rega, r'\1', content, flags=re.MULTILINE)
# FINISH
content = content.strip()
ff.write(content)
# Write into a file
ff.write(content.strip())
if logger:
logger.info(f'ending. writing to a file///////////////')
if logger: logger.info(f'ending. writing to a file///////////////')
return content
if logger: logger.error(f'Error in main')
if logger:
logger.error(f'Error in main')
@click.command()
@ -650,13 +749,27 @@ if __name__ == '__main__':
cli()
elif my_mode == 'debug-mode':
main(files_to_include=[0, 1, 2, 3],
output_name='johnson_n_johnson.txt',
output_name='OUTPUT.txt',
delete_html_comments=True)
elif my_mode == 'debug-mode2':
import logging; logger = logging.getLogger(__name__); logger.setLevel(logging.DEBUG)
my_file = logging.FileHandler('usage.log.txt', mode='w'); my_file.setLevel(logging.DEBUG)
log_file_name = 'usage.log.txt'
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
my_file = logging.FileHandler(log_file_name, mode='w')
my_file.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s>%(levelname)s: %(message)s')
my_file.setFormatter(formatter); logger.addHandler(my_file);
my_file.setFormatter(formatter); logger.addHandler(my_file)
main(logger=logger, files_to_include=[1],
output_name='johnson_n_johnson.txt',
output_name='OUTPUT.txt',
delete_html_comments=True)
'''
notes:
Как оказалось, декоратор @property делает из метода вот что:
- isdatadescriptor(class.method_as_property) вернет True
'''

60
readme_creator/pep8ify.py Normal file
View File

@ -0,0 +1,60 @@
import inspect
import PySimpleGUIlib
"""
Create All Possible Tags
Will output to STDOUT all of the different tags for classes, members and functions for a given PySimpleGUIlib.py
file. Functions that begin with _ are filtered out from the list.
Displays the results in a PySimpleGUI window which can be used to copy and paste into other places.
"""
def new_name(name):
name = name.replace("OK", "*1")
name = name.replace("TK", "*2")
name = name.replace("RGB", "*3")
new = name[0].lower()
for c in name[1:]:
new += '_' + c.lower() if (c.isupper() or c == "*") else c
new=new.replace("*1", "ok")
new = new.replace("*2", "tk")
new = new.replace("*3", "rgb")
return new
layout = [[PySimpleGUIlib.Output(size=(600,300))]]
window = PySimpleGUIlib.Window('Dump of tags', layout, resizable=True).Finalize()
psg_members = inspect.getmembers(PySimpleGUIlib)
psg_funcs = [o for o in psg_members if inspect.isfunction(o[1])]
psg_classes = [o for o in psg_members if inspect.isclass(o[1])]
# I don't know how this magic filtering works, I just know it works. "Private" stuff (begins with _) are somehow
# excluded from the list with the following 2 lines of code. Very nicely done Kol-ee-ya!
psg_classes_ = list(set([i[1] for i in psg_classes])) # filtering of anything that starts with _ (methods, classes, etc)
psg_classes = list(zip([i.__name__ for i in psg_classes_], psg_classes_))
for pclass in sorted(psg_classes):
if 'Tk' in pclass[0] or 'TK' in pclass[0] or 'Element' == pclass[0]: # or 'Window' == i[0]:
continue
# print(f'### {pclass[0]} Element')
# print('')
# print(f'<!-- <+{pclass[0]}.doc+> -->')
# print(f'<!-- <+{pclass[0]}.__init__+> -->')
print('')
print(f'{pclass[0]} methods in PEP8 format --------------------------------------')
for funcs in inspect.getmembers(pclass[1]):
if '_' not in funcs[0]:
# print(f'{pclass[0]}.{new_name(funcs[0])} = {pclass[0]}.{funcs[0]}') # version that has class on front
print(f'{new_name(funcs[0])} = {funcs[0]}') # version without class on front (use for most)
# print('\n'.join([f"#### {j[0]}\n\n<!-- <+{pclass[0]}.{j[0]}+> -->\n" for j in inspect.getmembers(pclass[1]) if '_' not in j[0]]))
# print('\n------------------------- Functions start here -------------------------\n')
#
for f in psg_funcs:
if f[0][0] == '_':
continue
print(f'{new_name(f[0])} = {f[0]}')
# print(f"<!-- <+func.{f[0]}+> -->")
window.Read()

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,7 @@ for i in sorted(psg_classes):
print('\n------------------------- Functions start here -------------------------\n')
for f in psg_funcs:
if f[0][0] == '_':
continue
print(f"<!-- <+func.{f[0]}+> -->")
if '_' != f[0][0]: # if doesn't START with _
print(f"<!-- <+func.{f[0]}+> -->")
window.Read()