Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
62b3faa
Refactor: update examples to reflect new 'allow_cell_edits'
ssweber Jun 29, 2023
7e57636
Ruff: ignore `value == ""` rule
ssweber Jun 29, 2023
c0d116c
Create jackcess-4.0.5.jar
ssweber Jun 29, 2023
47888cd
Fix: Correct `Ready` msgs for docker_util
ssweber Jun 29, 2023
c040cf2
Feat: New multi-db orders example
ssweber Jun 29, 2023
7196c3d
Feat: install_java, save previous jre install
ssweber Jun 29, 2023
a95f600
Refactor: remove triggers from orders.py, align closer to multidb orders
ssweber Jun 29, 2023
b9bebd5
nit: pd.options formatting
ssweber Jun 29, 2023
3d224a0
nit: imports
ssweber Jun 29, 2023
f2f0610
nit: new constant TYPE_INFO
ssweber Jun 29, 2023
e2a02d1
Fix: new constant EMPTY
ssweber Jun 29, 2023
a436909
Refactor: change datetype str to CONSTANTS
ssweber Jun 29, 2023
0bd86a6
Refactor: Relationship to dataclass and reorder to be like other classes
ssweber Jun 29, 2023
6336cd5
Refactor: Elementmap to dataclass
ssweber Jun 29, 2023
d990156
Fix: _invoke_callback
ssweber Jun 29, 2023
e42a7b4
Rename: 'current_row_updated' -> after_record_edit
ssweber Jun 29, 2023
ab28a19
Feat: new `column_info_settings` for quick_editor
ssweber Jun 29, 2023
7fd808e
Feat: Info StatusBar for quick_editor
ssweber Jun 29, 2023
5b7baf8
Feat: an `info_element`
ssweber Jun 29, 2023
8123e87
Big Feat: refactor Column and add new specialized Col classes
ssweber Jun 29, 2023
fa7898a
Fix: bool column mapping was broken
ssweber Jun 29, 2023
203f7e9
Fix: I broke sorting
ssweber Jun 29, 2023
171014f
Refactor: use new python_type vs domain
ssweber Jun 29, 2023
31b485a
Refactor/Feat: SqlDriver
ssweber Jun 29, 2023
2d9a588
Refactor/Feat/Fix: Sqlite driver
ssweber Jun 29, 2023
feff8b3
Refactor/Feat: MysqlDriver
ssweber Jun 29, 2023
c12336b
Feat/Refactor: Postgres driver
ssweber Jun 29, 2023
5673f4e
Refactor/Feat: SqlServer
ssweber Jun 29, 2023
7ce0f5e
Refactor/Feat: MsAccess driver
ssweber Jun 29, 2023
8046301
Nit: forgot line in sqlite driver
ssweber Jun 29, 2023
090754b
Refactor _looks_like_a_function to use SQL_CONSTANTS and simpler regex
ssweber Jun 29, 2023
8dbe5f8
Feat: _shake_animation
ssweber Jun 29, 2023
a498ee2
Refactor: _PlaceholderText
ssweber Jun 29, 2023
f74f37d
Refactor: Reuse code in Combo classes
ssweber Jun 29, 2023
5db5ddc
Fix: broken datepicker entry
ssweber Jun 29, 2023
2acff59
Nit: use tk contants in DatePicker
ssweber Jun 29, 2023
eb1e698
Feat: use cast in DatePicker
ssweber Jun 29, 2023
52410de
Rename TableHeading args
ssweber Jun 29, 2023
797e28a
Feat: New Validate classes
ssweber Jun 29, 2023
9a56a35
Feat: Use Validate and _shake_animation
ssweber Jun 29, 2023
68f24a3
Nit: ruff fix
ssweber Jun 29, 2023
0673ace
Fix: use get_pk_ignore_placeholder in LiveUpdate
ssweber Jun 29, 2023
6c4dbc9
Update Themepack to match new features
ssweber Jun 29, 2023
0335ed3
Update LanguagePack to use new features
ssweber Jun 29, 2023
ddd835d
Nit: remove order=True
ssweber Jun 29, 2023
41806da
Feat: Add validate checking before save to DataSet save_records
ssweber Jun 29, 2023
abd9fbf
Refactor: new Dataset function validate_field
ssweber Jun 30, 2023
0a8bc70
Fix: _shake_animation, don't move other elements
ssweber Jul 1, 2023
63a20db
Refactor/ allow validate exception animation to be more easily changed
ssweber Jul 2, 2023
0b936f1
Nit: change indent
ssweber Jul 2, 2023
98410a8
Feat: Allow passing column attrs to quick_editor in fields
ssweber Jul 2, 2023
4d75beb
Nit: change default Column python_type to object, ditch the special-c…
ssweber Jul 2, 2023
ecd6c8e
Better Sqlite Column mapping
ssweber Jul 5, 2023
12e1b22
Feat: adapters for date/datetime/time sqlite
ssweber Jul 5, 2023
b10cc21
Convert all Col classes to dataclasses, use __post_init__ to assign d…
ssweber Jul 5, 2023
826e306
Nit: ruff formatting
ssweber Jul 5, 2023
7e1abe1
Fix: typing hint
ssweber Jul 5, 2023
01c7b11
Cleanup: ColClasses
ssweber Jul 6, 2023
04f4e33
Cleanup: DecimalCol
ssweber Jul 6, 2023
9a27cdc
Refactor: popup
ssweber Jul 6, 2023
b20cfc9
Fixes for examples
ssweber Jul 7, 2023
27b0b46
Fix: Move transform above validate in DataSet.save_record
ssweber Jul 8, 2023
00ada45
Ruff fix
ssweber Jul 8, 2023
e130d46
Fix/Simplify: _invoke_callback
ssweber Jul 8, 2023
82ee0c9
Ruff: enable pandas-vet, pep8-naming
ssweber Jul 8, 2023
450a270
Ruff: enable #flake8-comprehensions, #flake8-bugbear
ssweber Jul 8, 2023
85b75fa
Ruff: Enable 'PIE'
ssweber Jul 8, 2023
3d8c711
Ruff: Enable NPY rules
ssweber Jul 8, 2023
cf1a2a2
Ruff: Enable Ruff rules
ssweber Jul 8, 2023
14f082a
Added a STRICT validate mode
ssweber Jul 9, 2023
c6c8d8c
nit: black fix
ssweber Jul 9, 2023
20fabfb
Feat: Better Locale for Column Casting
ssweber Jul 9, 2023
3bab944
Feat: Cell Formatting in table-values!
ssweber Jul 10, 2023
8962ce2
TableHeadings -> TableBuilder (#339)
ssweber Jul 11, 2023
b629b11
Nit: col/headings_justification / anchor cleanup
ssweber Jul 12, 2023
c9e286d
Update sqlite-only orders.py to match multiple
ssweber Jul 12, 2023
1c86e8f
Refactor DataSet as dataclass, add _LastSearch class
ssweber Jul 14, 2023
f0165a9
Cleanup constants
ssweber Jul 14, 2023
feaaa22
convert Form to a dataclass
ssweber Jul 14, 2023
80fe73e
ruff fix
ssweber Jul 14, 2023
646f6cb
Fix: Don't generate __eq__ for DataSet
ssweber Jul 17, 2023
8204108
Fix: Don't add __eq__ to Form either
ssweber Jul 17, 2023
53a8dec
Fix: Don't close quick_editor until frm has refreshed
ssweber Jul 17, 2023
732eb00
Work on Relationship
ssweber Jul 17, 2023
33e5321
Revert "Work on Relationship"
ssweber Jul 18, 2023
ef6d964
Fix converted dataclass (DataSet/Form/TableBuilder)
ssweber Jul 20, 2023
b109077
Convert SqlDrivers to Dataclasses, and Move Relationships to Driver
ssweber Jul 20, 2023
4ad29a4
Fixes for MsAccess
ssweber Jul 20, 2023
02494a0
Ruff/Black fixes
ssweber Jul 20, 2023
90f3130
Move MsAccess adapters/converters to an extendable framework
ssweber Jul 20, 2023
163f9fd
Fix for Postgres, use pk/pk_column
ssweber Jul 20, 2023
f11d229
Remove redundant `insert_record` in msaccess
ssweber Jul 20, 2023
cd3f543
Fix: Small fix for pk column
ssweber Jul 20, 2023
0237aa4
Fix: Remove quick_editor Form from Form Instances
ssweber Jul 20, 2023
909a1f6
Fix: Convert numpy.int64 to int correctly
ssweber Jul 20, 2023
21a156b
Ruff/Black fixes
ssweber Jul 20, 2023
47cb650
Fixes for opening a database without any records
ssweber Jul 21, 2023
eca1d30
Fix Postgres, get columns in order of creation (like other drivers)
ssweber Jul 21, 2023
39f598b
Remove prefix_data_keys Form init option
ssweber Jul 21, 2023
6dd1d56
Rows will always have (at least) an empty dataframe
ssweber Jul 21, 2023
d34ed78
Feat: add `close_driver` arg to Form.close()
ssweber Jul 21, 2023
9660376
Update ColumnInfo example
ssweber Jul 21, 2023
a62404a
Make a few more classes Private
ssweber Jul 23, 2023
2f5f436
Ruff/Black
ssweber Jul 23, 2023
33cb428
Ruff fixes (had to upgrade to match github action
ssweber Jul 23, 2023
e17857d
Convert to Google-style docstrings
ssweber Jul 25, 2023
62c5887
Update .git-blame-ignore-revs
ssweber Jul 25, 2023
079f9a5
Change mkdocstrings to google
ssweber Jul 25, 2023
49a213e
Rename _LastSearch to _PrevSearch
ssweber Jul 26, 2023
f17b54a
Docs
ssweber Jul 26, 2023
95de050
Docs
ssweber Jul 26, 2023
56f08ab
Large Docs update (#341)
ssweber Aug 3, 2023
8f02b80
nits
ssweber Aug 3, 2023
9736f01
Update .gitignore
ssweber Aug 4, 2023
744ebe7
Move `current` functions under DataSet.current
ssweber Aug 6, 2023
9d11bdf
Refactor current.get_pk() -> `@property current.pk
ssweber Aug 7, 2023
1045a56
Update pysimplesql.py
ssweber Aug 7, 2023
043ea12
Black fix
ssweber Sep 18, 2023
91840fd
get ruff to pass
ssweber Sep 20, 2023
e599862
More ruff fixes (new version disallows comparing with "is"
ssweber Sep 20, 2023
cc64643
black fix
ssweber Sep 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ cb040bf0656ab6b3c019fadc6adf98c7d4ba01ea
f7addad546672815db9293f772db71c57521f8e8
fbeec4c4322b7a1f8dc4cd82ac3c10e6c313901a

# google style docstrings
e17857d4369d57961b6f75385fd1e5a1d2434869
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,17 @@ cython_debug/
# Ignore the lib folder for pysimplesql
!**pysimplesql/lib/
!**pysimplesql/lib/**

# Ignore vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets

# Local History for Visual Studio Code
.history/

# Built Visual Studio Code Extensions
*.vsix
42 changes: 42 additions & 0 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions .libcst.codemod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# String that LibCST should look for in code which indicates that the
# module is generated code.
generated_code_marker: '@generated'
# Command line and arguments for invoking a code formatter. Anything
# specified here must be capable of taking code via stdin and returning
# formatted code via stdout.
formatter: ['black', '-']
# List of regex patterns which LibCST will evaluate against filenames to
# determine if the module should be touched.
blacklist_patterns: []
# List of modules that contain codemods inside of them.
modules:
- 'libcst.codemod.commands'- 'autotyping'
# Absolute or relative path of the repository root, used for providing
# full-repo metadata. Relative paths should be specified with this file
# location as the base.
repo_root: '.'
Expand Down
25 changes: 10 additions & 15 deletions doc_examples/ColumnInfo.1.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
# Set the null value default for INTEGERS to 10;
# Set the null value default for 'int' to 10;
# When reading from the database, if an INTEGER is Null, this value will be set
frm["Journal"].column_info.set_null_default("INTEGER", 10)
frm["Journal"].column_info.set_null_default("int", 10)

# Provide a complete custom set of null defaults:
# note: All supported keys must be included
null_defaults = {
"TEXT": "New Record",
"VARCHAR": "New Record",
"CHAR": "New Record",
"INTEGER": 10,
"REAL": 100.0,
"DOUBLE": 90.0,
"FLOAT": 80.0,
"DECIMAL": 70.0,
"BOOLEAN": 1,
"TIME": lambda x: datetime.now().strftime("%H:%M:%S"),
"DATE": lambda x: date.today().strftime("%Y-%m-%d"),
"TIMESTAMP": lambda x: datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"DATETIME": lambda x: datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"str": lang.description_column_str_null_default,
"int": 10,
"float": 90.0,
"Decimal": Decimal("70.0"),
"bool": 1,
"time": lambda: dt.datetime.now().strftime(TIME_FORMAT),
"date": lambda: dt.date.today().strftime(DATE_FORMAT),
"datetime": lambda: dt.datetime.now().strftime(DATETIME_FORMAT),
}
frm["Journal"].column_info.set_null_defaults(null_defaults)
36 changes: 36 additions & 0 deletions doc_scripts/griffe_extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import ast
import re

from griffe import Extension, Object, ObjectNode


class RegexUrl(Extension):
IGNORE = ["sg"] #

def regex_replace(self, input_string: str, regex_pattern, prefix: str):
compiled_pattern = re.compile(regex_pattern)

def replace_function(match):
parts = match.group(1).split(".")
if any(parts[0].startswith(prefix) for prefix in self.IGNORE):
return match.group(0)

# get text section of url, we will only use the last obj
text = parts[-1]

fn_suffix = ""
if match.group(2):
# pass () as html encoding
fn_suffix = "()"
complete_path = prefix + match.group(1)
return f"[{text}{fn_suffix}][{complete_path}]"

return compiled_pattern.sub(replace_function, input_string)

def on_instance(self, node: ast.AST | ObjectNode, obj: Object) -> None:
if obj.docstring:
# regex pattern matches a valid non-private class name or function, with or without a '()' at the end
regex_pattern = r"\`([A-Za-z][A-Za-z0-9_.]*)(\(\))*\`"
obj.docstring.value = self.regex_replace(
obj.docstring.value, regex_pattern, "pysimplesql.pysimplesql."
)
20 changes: 4 additions & 16 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
# Welcome to MkDocs
# API Reference (more pages to come)

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

mkdocs.yml # The configuration file.
docs/
index.md # The documentation homepage.
... # Other markdown pages, images and other files.
::: pysimplesql.pysimplesql
options:
members_order: source
3 changes: 0 additions & 3 deletions docs/pysimplesql.md

This file was deleted.

12 changes: 6 additions & 6 deletions examples/Flatfile_examples/csv_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
# Create a simple layout for working with our flatfile data.
# Note that you can set a specific table name to use, but here I am just using the defaul 'Flatfile'
# Lets also use some sortable headers so that we can rearrange the flatfile data when saving
headings=ss.TableHeadings(sort_enable=True)
headings.add_column('name', 'Name', width=12)
headings.add_column('address', 'Address', width=25)
headings.add_column('phone', 'Phone #', width=10)
headings.add_column('email', 'EMail', width=25)
table_builder = ss.TableBuilder(num_rows=10)
table_builder.add_column('name', 'Name', width=12)
table_builder.add_column('address', 'Address', width=25)
table_builder.add_column('phone', 'Phone #', width=10)
table_builder.add_column('email', 'EMail', width=25)

layout = [
[ss.selector('Flatfile', sg.Table, num_rows=10, headings=headings)],
[ss.selector('Flatfile', table_builder)],
[ss.field('Flatfile.name')],
[ss.field('Flatfile.address')],
[ss.field('Flatfile.phone')],
Expand Down
42 changes: 40 additions & 2 deletions examples/MSAccess_examples/install_java.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
run. This also serves as an example to automatically download a local Java installation
for your own projects.
"""
import configparser
import os
import pathlib
import pysimplesql as ss
import PySimpleGUI as sg
import subprocess
Expand All @@ -17,11 +19,19 @@
sg.popup_error("You must `pip install install-jdk` to use this example")
exit(0)

SETTINGS_FILE = pathlib.Path.cwd() / "settings.ini"


# -------------------------------------------------
# ROUTINES TO INSTALL JAVA IF USER DOES NOT HAVE IT
# -------------------------------------------------
def _is_java_installed():
def _is_java_installed() -> bool:
if "JAVA_HOME" in os.environ:
return True
previous_jre = load_setting("General", "java_home")
if previous_jre:
os.environ["JAVA_HOME"] = previous_jre
return True
# Returns True if Java is installed, False otherwise
try:
subprocess.check_output(["which", "java"])
Expand Down Expand Up @@ -64,8 +74,9 @@ def java_check_install() -> bool:
pa.close()
return False
pa.close()
# set JAVA_HOME
# Set JAVA_HOME and save it to settings
os.environ["JAVA_HOME"] = java_home
save_setting("General", "java_home", java_home)
else:
url = jdk.get_download_url(11, jre=True)
sg.popup(
Expand All @@ -80,6 +91,33 @@ def java_check_install() -> bool:
return True


def save_setting(section: str, key: str, value: str) -> None:
config = configparser.ConfigParser()
config.read(SETTINGS_FILE)

# Create the section if it doesn't exist
if section not in config:
config[section] = {}

# Set the value in the section
config[section][key] = value

# Save the settings to the file
with open(SETTINGS_FILE, "w") as config_file:
config.write(config_file)


def load_setting(section: str, key: str, default=None) -> str:
config = configparser.ConfigParser()
config.read(SETTINGS_FILE)

# Check if the section and key exist
if section in config and key in config[section]:
return config[section][key]

return default


if __name__ == "__main__":
if java_check_install():
print("Java is installed.")
Expand Down
10 changes: 5 additions & 5 deletions examples/MSAccess_examples/journal_msaccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
# -------------------------
# Define the columns for the table selector using the TableHeading convenience class.
# This will also allow sorting!
headings = ss.TableHeadings(sort_enable=True)
headings.add_column("title", "Title", width=40)
headings.add_column("entry_date", "Date", width=10)
headings.add_column("mood_id", "Mood", width=20)
table_builder = ss.TableBuilder(num_rows=10)
table_builder.add_column("title", "Title", width=40)
table_builder.add_column("entry_date", "Date", width=10)
table_builder.add_column("mood_id", "Mood", width=20)

layout = [
[ss.selector("Journal", sg.Table, num_rows=10, headings=headings)],
[ss.selector("Journal", table_builder)],
[ss.actions("Journal")],
[
ss.field("Journal.entry_date"),
Expand Down
2 changes: 1 addition & 1 deletion examples/MySQL_examples/docker/Docker_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
with tqdm(desc="Starting up container") as pbar:
container.reload()
while True:
if "Status" in container.attrs["State"]: # noqa: SIM102
if "Status" in container.attrs["State"]:
if container.attrs["State"]["Status"] == "running":
break
time.sleep(1)
Expand Down
10 changes: 5 additions & 5 deletions examples/MySQL_examples/journal_mysql_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
# -------------------------
# Define the columns for the table selector using the TableHeading convenience class.
# This will also allow sorting!
headings = ss.TableHeadings(sort_enable=True)
headings.add_column("title", "Title", width=40)
headings.add_column("entry_date", "Date", width=10)
headings.add_column("mood_id", "Mood", width=20)
table_builder = ss.TableBuilder(num_rows=10)
table_builder.add_column("title", "Title", width=40)
table_builder.add_column("entry_date", "Date", width=10)
table_builder.add_column("mood_id", "Mood", width=20)

layout = [
[ss.selector("Journal", sg.Table, num_rows=10, headings=headings)],
[ss.selector("Journal", table_builder)],
[ss.actions("Journal")],
[
ss.field("Journal.entry_date"),
Expand Down
2 changes: 1 addition & 1 deletion examples/PostgreSQL_examples/docker/Docker_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
with tqdm(desc="Starting up container") as pbar:
container.reload()
while True:
if "Status" in container.attrs["State"]: # noqa: SIM102
if "Status" in container.attrs["State"]:
if container.attrs["State"]["Status"] == "running":
break
time.sleep(1)
Expand Down
10 changes: 5 additions & 5 deletions examples/PostgreSQL_examples/journal_postgres_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
# -------------------------
# Define the columns for the table selector using the TableHeading convenience class.
# This will also allow sorting!
headings = ss.TableHeadings(sort_enable=True)
headings.add_column("title", "Title", width=40)
headings.add_column("entry_date", "Date", width=10)
headings.add_column("mood_id", "Mood", width=20)
table_builder = ss.TableBuilder(num_rows=10)
table_builder.add_column("title", "Title", width=40)
table_builder.add_column("entry_date", "Date", width=10)
table_builder.add_column("mood_id", "Mood", width=20)

layout = [
[ss.selector("Journal", sg.Table, num_rows=10, headings=headings)],
[ss.selector("Journal", table_builder)],
[ss.actions("Journal")],
[
ss.field("Journal.entry_date"),
Expand Down
Loading