Anthony Truchet commited on
Commit
aed86da
·
1 Parent(s): 49b1b27

feat: add quality tooling around Poetry

Browse files
.flake8 ADDED
@@ -0,0 +1 @@
 
 
1
+ pkg/.flake8
.gitignore CHANGED
@@ -1,4 +1,118 @@
1
- venv/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  # Byte-compiled / optimized / DLL files
3
  __pycache__/
4
  *.py[cod]
@@ -21,12 +135,10 @@ parts/
21
  sdist/
22
  var/
23
  wheels/
24
- pip-wheel-metadata/
25
- share/python-wheels/
26
  *.egg-info/
27
  .installed.cfg
28
  *.egg
29
- MANIFEST
30
 
31
  # PyInstaller
32
  # Usually these files are written by a python script from a template
@@ -41,27 +153,19 @@ pip-delete-this-directory.txt
41
  # Unit test / coverage reports
42
  htmlcov/
43
  .tox/
44
- .nox/
45
  .coverage
46
  .coverage.*
47
  .cache
 
48
  nosetests.xml
49
  coverage.xml
50
  *.cover
51
- *.py,cover
52
  .hypothesis/
53
- .pytest_cache/
54
 
55
  # Translations
56
  *.mo
57
  *.pot
58
 
59
- # Django stuff:
60
- *.log
61
- local_settings.py
62
- db.sqlite3
63
- db.sqlite3-journal
64
-
65
  # Flask stuff:
66
  instance/
67
  .webassets-cache
@@ -78,26 +182,11 @@ target/
78
  # Jupyter Notebook
79
  .ipynb_checkpoints
80
 
81
- # IPython
82
- profile_default/
83
- ipython_config.py
84
-
85
  # pyenv
86
  .python-version
87
 
88
- # pipenv
89
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
91
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
92
- # install all needed dependencies.
93
- #Pipfile.lock
94
-
95
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow
96
- __pypackages__/
97
-
98
- # Celery stuff
99
- celerybeat-schedule
100
- celerybeat.pid
101
 
102
  # SageMath parsed files
103
  *.sage.py
@@ -123,12 +212,38 @@ venv.bak/
123
 
124
  # mypy
125
  .mypy_cache/
126
- .dmypy.json
127
- dmypy.json
128
 
129
- # Pyre type checker
130
- .pyre/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
- .vscode/
133
 
134
- data/audio/
 
1
+ pkg/doc/_autosummary
2
+
3
+ .envrc
4
+ .idea
5
+
6
+ # Created by https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
7
+
8
+ ### Linux ###
9
+ *~
10
+
11
+ # temporary files which can be created if a process still has a handle open of a deleted file
12
+ .fuse_hidden*
13
+
14
+ # KDE directory preferences
15
+ .directory
16
+
17
+ # Linux trash folder which might appear on any partition or disk
18
+ .Trash-*
19
+
20
+ # .nfs files are created when an open file is removed but is still being accessed
21
+ .nfs*
22
+
23
+ ### OSX ###
24
+ *.DS_Store
25
+ .AppleDouble
26
+ .LSOverride
27
+
28
+ # Icon must end with two \r
29
+ Icon
30
+
31
+ # Thumbnails
32
+ ._*
33
+
34
+ # Files that might appear in the root of a volume
35
+ .DocumentRevisions-V100
36
+ .fseventsd
37
+ .Spotlight-V100
38
+ .TemporaryItems
39
+ .Trashes
40
+ .VolumeIcon.icns
41
+ .com.apple.timemachine.donotpresent
42
+
43
+ # Directories potentially created on remote AFP share
44
+ .AppleDB
45
+ .AppleDesktop
46
+ Network Trash Folder
47
+ Temporary Items
48
+ .apdisk
49
+
50
+ ### PyCharm ###
51
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
52
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
53
+
54
+ # User-specific stuff:
55
+ .idea/**/workspace.xml
56
+ .idea/**/tasks.xml
57
+ .idea/dictionaries
58
+
59
+ # Sensitive or high-churn files:
60
+ .idea/**/dataSources/
61
+ .idea/**/dataSources.ids
62
+ .idea/**/dataSources.xml
63
+ .idea/**/dataSources.local.xml
64
+ .idea/**/sqlDataSources.xml
65
+ .idea/**/dynamic.xml
66
+ .idea/**/uiDesigner.xml
67
+
68
+ # Gradle:
69
+ .idea/**/gradle.xml
70
+ .idea/**/libraries
71
+
72
+ # CMake
73
+ cmake-build-debug/
74
+
75
+ # Mongo Explorer plugin:
76
+ .idea/**/mongoSettings.xml
77
+
78
+ ## File-based project format:
79
+ *.iws
80
+
81
+ ## Plugin-specific files:
82
+
83
+ # IntelliJ
84
+ /out/
85
+
86
+ # mpeltonen/sbt-idea plugin
87
+ .idea_modules/
88
+
89
+ # JIRA plugin
90
+ atlassian-ide-plugin.xml
91
+
92
+ # Cursive Clojure plugin
93
+ .idea/replstate.xml
94
+
95
+ # Ruby plugin and RubyMine
96
+ /.rakeTasks
97
+
98
+ # Crashlytics plugin (for Android Studio and IntelliJ)
99
+ com_crashlytics_export_strings.xml
100
+ crashlytics.properties
101
+ crashlytics-build.properties
102
+ fabric.properties
103
+
104
+ ### PyCharm Patch ###
105
+ # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
106
+
107
+ # *.iml
108
+ # modules.xml
109
+ # .idea/misc.xml
110
+ # *.ipr
111
+
112
+ # Sonarlint plugin
113
+ .idea/sonarlint
114
+
115
+ ### Python ###
116
  # Byte-compiled / optimized / DLL files
117
  __pycache__/
118
  *.py[cod]
 
135
  sdist/
136
  var/
137
  wheels/
 
 
138
  *.egg-info/
139
  .installed.cfg
140
  *.egg
141
+ /*.zip
142
 
143
  # PyInstaller
144
  # Usually these files are written by a python script from a template
 
153
  # Unit test / coverage reports
154
  htmlcov/
155
  .tox/
 
156
  .coverage
157
  .coverage.*
158
  .cache
159
+ .pytest_cache/
160
  nosetests.xml
161
  coverage.xml
162
  *.cover
 
163
  .hypothesis/
 
164
 
165
  # Translations
166
  *.mo
167
  *.pot
168
 
 
 
 
 
 
 
169
  # Flask stuff:
170
  instance/
171
  .webassets-cache
 
182
  # Jupyter Notebook
183
  .ipynb_checkpoints
184
 
 
 
 
 
185
  # pyenv
186
  .python-version
187
 
188
+ # celery beat schedule file
189
+ celerybeat-schedule.*
 
 
 
 
 
 
 
 
 
 
 
190
 
191
  # SageMath parsed files
192
  *.sage.py
 
212
 
213
  # mypy
214
  .mypy_cache/
 
 
215
 
216
+ ### VisualStudioCode ###
217
+ .vscode/*
218
+ !.vscode/settings.json
219
+ !.vscode/tasks.json
220
+ !.vscode/launch.json
221
+ !.vscode/extensions.json
222
+ .history
223
+
224
+ ### Windows ###
225
+ # Windows thumbnail cache files
226
+ Thumbs.db
227
+ ehthumbs.db
228
+ ehthumbs_vista.db
229
+
230
+ # Folder config file
231
+ Desktop.ini
232
+
233
+ # Recycle Bin used on file shares
234
+ $RECYCLE.BIN/
235
+
236
+ # Windows Installer files
237
+ *.cab
238
+ *.msi
239
+ *.msm
240
+ *.msp
241
+
242
+ # Windows shortcuts
243
+ *.lnk
244
+
245
+ # Build folder
246
 
247
+ */build/*
248
 
249
+ # End of https://www.gitignore.io/api/osx,linux,python,windows,pycharm,visualstudiocode
.pre-commit-config.yaml ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v4.4.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: check-added-large-files
7
+ name: Check for added large files
8
+ entry: check-added-large-files
9
+ - id: check-toml
10
+ name: Check Toml
11
+ entry: check-toml
12
+ types: [toml]
13
+ - id: check-yaml
14
+ name: Check Yaml
15
+ entry: check-yaml
16
+ types: [yaml]
17
+ - id: end-of-file-fixer
18
+ name: Fix End of Files
19
+ entry: end-of-file-fixer
20
+ types: [text]
21
+ stages: [commit, push, manual]
22
+ - id: trailing-whitespace
23
+ name: Trim Trailing Whitespace
24
+ entry: trailing-whitespace-fixer
25
+ types: [text]
26
+ stages: [commit, push, manual]
27
+
28
+ - repo: https://github.com/mwouts/jupytext
29
+ rev: v1.14.6
30
+ hooks:
31
+ - id: jupytext
32
+ name: jupytext (sync existing Notebooks)
33
+ entry: jupytext
34
+ language: python
35
+ args: [--sync, --pipe, black, --pre-commit]
36
+ pass_filenames: false
37
+ additional_dependencies:
38
+ - black==23.3.0
39
+
40
+ - repo: https://github.com/psf/black
41
+ rev: 23.3.0
42
+ hooks:
43
+ - id: black
44
+ name: black
45
+ entry: black
46
+ types: [python]
47
+ require_serial: true
48
+
49
+ - repo: https://github.com/pycqa/isort
50
+ rev: 5.12.0
51
+ hooks:
52
+ - id: isort
53
+ name: isort
54
+ entry: isort
55
+ require_serial: true
56
+ language: python
57
+ types_or: [cython, pyi, python]
58
+ args: ["--profile", "black", "--filter-files"]
59
+
60
+ - repo: https://github.com/pycqa/flake8
61
+ rev: "6.0.0"
62
+ hooks:
63
+ - id: flake8
64
+ name: flake8
65
+ entry: flake8
66
+ types: [python]
67
+ require_serial: true
68
+ exclude: "jupyter/scripts"
69
+
70
+ - repo: https://github.com/asottile/pyupgrade
71
+ rev: v3.7.0
72
+ hooks:
73
+ - id: pyupgrade
74
+ name: pyupgrade
75
+ description: Automatically upgrade syntax for newer versions.
76
+ entry: pyupgrade
77
+ types: [python]
78
+ args: [--py39-plus]
79
+
80
+ - repo: https://github.com/commitizen-tools/commitizen
81
+ rev: 3.5.2
82
+ hooks:
83
+ - id: commitizen
84
+ - id: commitizen-branch
85
+ stages: [push]
86
+ - repo: https://github.com/python-poetry/poetry
87
+ rev: '1.5.0'
88
+ hooks:
89
+ - id: poetry-check
90
+ # - id: poetry-lock
91
+ # - id: poetry-export
92
+ # files: "pyproject.toml,requirements.txt"
93
+ # args: ["-f", "requirements.txt", "-o", "requirements.txt", "--without-hashes", "--only=main"]
Dockerfile CHANGED
@@ -10,7 +10,7 @@ RUN pip3 install --upgrade pip
10
  RUN pip3 install --no-cache-dir -r /app/requirements.txt
11
 
12
  # Persistent disk space
13
- # see https://huggingface.co/docs/hub/spaces-storage
14
  RUN mkdir -p /data/.huggingface
15
  ENV HF_HOME /data/.huggingface
16
 
@@ -28,7 +28,7 @@ COPY . $HOME/app
28
 
29
  # Back to root to fix ownership and permissions
30
  USER root
31
- RUN chown user /data/.huggingface
32
  USER user
33
 
34
  # Expose streamlit application
 
10
  RUN pip3 install --no-cache-dir -r /app/requirements.txt
11
 
12
  # Persistent disk space
13
+ # see https://huggingface.co/docs/hub/spaces-storage
14
  RUN mkdir -p /data/.huggingface
15
  ENV HF_HOME /data/.huggingface
16
 
 
28
 
29
  # Back to root to fix ownership and permissions
30
  USER root
31
+ RUN chown user /data/.huggingface
32
  USER user
33
 
34
  # Expose streamlit application
README.md CHANGED
@@ -18,7 +18,7 @@ Code from https://docs.streamlit.io/library/get-started/create-an-app
18
  ## Local execution ##
19
 
20
  You need *Docker* installed.
21
- On MacOSX we recommand using *colima* if you do not want to use *Docker Desktop*
22
  for licensing reasons.
23
 
24
  * https://docs.docker.com/desktop/install/mac-install/
@@ -30,3 +30,160 @@ $ docker build -t persistent-docker-space .
30
  $ docker run -it -p 8501:8501 persistent-docker-space:latest
31
 
32
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  ## Local execution ##
19
 
20
  You need *Docker* installed.
21
+ On MacOSX we recommand using *colima* if you do not want to use *Docker Desktop*
22
  for licensing reasons.
23
 
24
  * https://docs.docker.com/desktop/install/mac-install/
 
30
  $ docker run -it -p 8501:8501 persistent-docker-space:latest
31
 
32
  ```
33
+
34
+ # Setting-up the developpers'tooling
35
+
36
+ ### Install `poetry`
37
+
38
+ https://python-poetry.org/
39
+
40
+ #### Linux and Mac
41
+
42
+ It should be straightforward with the official documentation
43
+
44
+ #### Windows (PowerShell)
45
+
46
+ ```shell
47
+ (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
48
+ ```
49
+
50
+ The execution will probably be stored at the address: `C:\User\<myUserName>\AppData\Roaming\pypoetry\venv\Scripts` and this
51
+ path should be included in the environment path of your machine in order to avoid typing it every time poetry is used.
52
+ To do so you can execute the following commands:
53
+
54
+ ```shell
55
+ $Env:Path += ";C:\Users\YourUserName\AppData\Roaming\Python\Scripts"
56
+ ```
57
+
58
+ This will only make the change in the path temporarily. In order to do it permanently you can execute the following command
59
+ ```shell
60
+ setx PATH "$Env:Path"
61
+ ```
62
+
63
+ ### Configuration of the `poetry` environment
64
+
65
+ After having installed poetry in your local machine, if there is already a `poetry.lock` file on your repository, you
66
+ can execute
67
+
68
+ ```shell
69
+ poetry install
70
+ ```
71
+
72
+ If it is not the case you can
73
+
74
+ ```shell
75
+ poetry init
76
+ poetry env use "whatever version of python you have in your local machine (compatible with the project)"
77
+ poetry shell
78
+ ```
79
+
80
+ ### pre-commit
81
+
82
+ https://pre-commit.com/
83
+
84
+ If there is already a `poetry.lock` file with `pre-commit` present in it, you should activate your poetry environment
85
+ and then install all the pre-commit hooks on your machine
86
+
87
+ ```shell
88
+ poetry shell
89
+ pre-commit install
90
+ pre-commit install --install-hooks
91
+ ```
92
+
93
+ If not, you should first add `pre-commit` to your poetry environment, and follow the steps above
94
+
95
+ ```shell
96
+ poetry add --group=dev pre-commit
97
+ ```
98
+
99
+ ### commitizen
100
+
101
+ https://www.conventionalcommits.org/en/about/
102
+
103
+ https://commitizen-tools.github.io/commitizen/
104
+
105
+
106
+ Commitizen will be installed as a pre-commit hook. In order for it to be executed before committing
107
+ you should run the following command (after activating your poetry environment)
108
+
109
+ ```shell
110
+ pre-commit install --hook-type commit-msg
111
+ ```
112
+
113
+ Finally, every time you will be committing, you should be places in your poetry environment and commitizen hooks
114
+ should be applied
115
+
116
+ ### testing
117
+
118
+ There are two different kinds of tests that can be run when testing the scripts: unit tests or doctest
119
+
120
+ These tests can be run by executing the following command:
121
+
122
+ ```shell
123
+ ./scripts/run-tests.sh
124
+ ```
125
+
126
+ #### pytest
127
+
128
+ https://docs.pytest.org/en/7.2.x/
129
+
130
+ These tests should be stored in the directory `tests` at the root of the project
131
+
132
+ #### xdoctest (driven by pytest)
133
+
134
+ These are the tests that are put in the docstrings of the functions accordingly to the following format:
135
+
136
+ ```python
137
+ def build_greetings(name: Optional[str] = None) -> str:
138
+ """
139
+ Return a greeting message, possibly customize with a name.
140
+
141
+ >>> build_greetings()
142
+ 'Hello, World!'
143
+ >>> build_greetings('Toto')
144
+ 'Nice to meet you, Toto!'
145
+ """
146
+ return name and f"Nice to meet you, {name}!" or "Hello, World!"
147
+ ```
148
+
149
+ The evaluated values would be the ones following the `>>>`
150
+
151
+ ### documentation
152
+
153
+ https://www.sphinx-doc.org/en/master/
154
+
155
+ In order to create an automatic documentation of your code you should run the bash script
156
+
157
+ ```shell
158
+ ./scripts/build-clean-docs.sh
159
+ ```
160
+
161
+ And in order to create an interactive session (web-server hosted in your local machine), you can execute the
162
+ following command
163
+
164
+ ```shell
165
+ ./scripts/interactive-rebuild-docs.sh
166
+ ```
167
+
168
+ Remark: In order to execute a bash script with a Windows OS, it is recommended to use a bash terminal emulator
169
+
170
+ ## Hugging Face
171
+
172
+ See instructions at https://huggingface.co/welcome
173
+
174
+ Install `huggingface_hub` into the poetry project.
175
+
176
+ ```shell
177
+ poetry add --group=dev huggingface_hub
178
+ ```
179
+
180
+ On MacOS, you might probably want to install `hugginface-cli` from brew :
181
+ ```shell
182
+ $ brew install huggingface-cli
183
+ ```
184
+
185
+ In order to deploy the streamlit app you will have to export
186
+ the poetry config as a `requirements.txt` :
187
+ ```shell
188
+ $ poetry export -o ../requirements.txt --without-hashes --only main
189
+ ```
app.py CHANGED
@@ -1,38 +1,48 @@
1
- import streamlit as st
2
- import pandas as pd
3
  import numpy as np
 
 
 
4
 
5
- st.title('Uber pickups in NYC')
 
 
 
 
 
 
6
 
7
- DATE_COLUMN = 'date/time'
8
- DATA_URL = ('https://s3-us-west-2.amazonaws.com/'
9
- 'streamlit-demo-data/uber-raw-data-sep14.csv.gz')
10
 
11
  @st.cache_resource
12
  def load_data(nrows):
13
  data = pd.read_csv(DATA_URL, nrows=nrows)
14
- lowercase = lambda x: str(x).lower()
15
- data.rename(lowercase, axis='columns', inplace=True)
 
 
 
16
  data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
17
  return data
18
 
19
- data_load_state = st.text('Loading data...')
 
20
  data = load_data(10000)
21
  data_load_state.text("Done! (using st.cache)")
22
 
23
- if st.checkbox('Show raw data'):
24
- st.subheader('Raw data')
25
  st.write(data)
26
 
27
- st.subheader('Number of pickups by hour')
28
- hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0]
 
 
29
  st.bar_chart(hist_values)
30
 
31
  # Some number in the range 0-23
32
- hour_to_filter = st.slider('hour', 0, 23, 17)
33
  filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]
34
 
35
- st.subheader('Map of all pickups at %s:00' % hour_to_filter)
36
  st.map(filtered_data)
37
 
38
  uploaded_file = st.file_uploader("Choose a file")
 
 
 
1
  import numpy as np
2
+ import pandas as pd
3
+ import streamlit as st
4
+
5
 
6
+ st.title("Uber pickups in NYC")
7
+
8
+ DATE_COLUMN = "date/time"
9
+ DATA_URL = (
10
+ "https://s3-us-west-2.amazonaws.com/"
11
+ "streamlit-demo-data/uber-raw-data-sep14.csv.gz"
12
+ )
13
 
 
 
 
14
 
15
  @st.cache_resource
16
  def load_data(nrows):
17
  data = pd.read_csv(DATA_URL, nrows=nrows)
18
+
19
+ def lowercase():
20
+ lambda x: str(x).lower()
21
+
22
+ data.rename(lowercase, axis="columns", inplace=True)
23
  data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
24
  return data
25
 
26
+
27
+ data_load_state = st.text("Loading data...")
28
  data = load_data(10000)
29
  data_load_state.text("Done! (using st.cache)")
30
 
31
+ if st.checkbox("Show raw data"):
32
+ st.subheader("Raw data")
33
  st.write(data)
34
 
35
+ st.subheader("Number of pickups by hour")
36
+ hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0, 24))[
37
+ 0
38
+ ]
39
  st.bar_chart(hist_values)
40
 
41
  # Some number in the range 0-23
42
+ hour_to_filter = st.slider("hour", 0, 23, 17)
43
  filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]
44
 
45
+ st.subheader("Map of all pickups at %s:00" % hour_to_filter)
46
  st.map(filtered_data)
47
 
48
  uploaded_file = st.file_uploader("Choose a file")
doc/_autosummary/athai.hello.rst ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ athai.hello
2
+ ===========
3
+
4
+ .. automodule:: athai.hello
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ .. rubric:: Functions
13
+
14
+ .. autosummary::
15
+
16
+ build_greetings
17
+ main
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
doc/_autosummary/athai.rst ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ athai
2
+ =====
3
+
4
+ .. automodule:: athai
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+ .. rubric:: Modules
25
+
26
+ .. autosummary::
27
+ :toctree:
28
+ :recursive:
29
+
30
+ athai.hello
31
+
doc/about.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==================
2
+ About this project
3
+ ==================
4
+
5
+ .. include:: ../README.md
6
+ :parser: myst_parser.sphinx_
7
+
8
+ Tooling
9
+ =======
10
+
11
+ .. todo::
12
+ Move notes from the ReadMe here and actually provide explanations
13
+
14
+
15
+ .. include:: ../jupyter/ReadMe.rst
doc/autosummary.rst ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ..
2
+ DO NOT DELETE THIS FILE! It contains the all-important `.. autosummary::` directive with `:recursive:` option, without
3
+ which API documentation wouldn't get extracted from docstrings by the `sphinx.ext.autosummary` engine. It is hidden
4
+ (not declared in any toctree) to remove an unnecessary intermediate page; index.rst instead points directly to the
5
+ package page. DO NOT REMOVE THIS FILE!
6
+
7
+ See https://github.com/JamesALeedham/Sphinx-Autosummary-Recursion for details
8
+
9
+
10
+ .. autosummary::
11
+ :toctree: _autosummary
12
+ :recursive:
13
+
14
+ athai
doc/conf.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ # -- Project information -----------------------------------------------------
7
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
+
9
+ project = "Template Python project"
10
+ copyright = "2023, Polyconseil"
11
+ author = "Anthony Truchet"
12
+ release = "0.1"
13
+
14
+ # -- General configuration ---------------------------------------------------
15
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
16
+
17
+ templates_path = ["_templates"]
18
+ exclude_patterns = []
19
+
20
+
21
+ extensions = [
22
+ "sphinx.ext.autodoc",
23
+ "sphinx.ext.autosummary",
24
+ "sphinx.ext.napoleon",
25
+ "sphinx.ext.todo",
26
+ "myst_parser",
27
+ "sphinx_rtd_theme",
28
+ ]
29
+
30
+ autodoc_typehints = "signature"
31
+ autodoc_default_options = {
32
+ "members": True,
33
+ "member-order": "bysource",
34
+ "special-members": "__call__",
35
+ "undoc-members": True,
36
+ "exclude-members": "__weakref__",
37
+ "show-inheritance": True,
38
+ "autodoc_typehints": "signature",
39
+ }
40
+
41
+ autosummary_generate = True
42
+
43
+ # https://www.sphinx-doc.org/en/master/usage/extensions/todo.html
44
+ todo_include_todos = True
45
+
46
+ # -- Options for HTML output -------------------------------------------------
47
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
48
+
49
+ # html_theme = 'alabaster'
50
+ html_theme = "sphinx_rtd_theme"
51
+
52
+ html_static_path = ["_static"]
doc/howto.rst ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ ==========
2
+ How to ...
3
+ ==========
4
+
5
+ .. py:currentmodule:: athai.hello
6
+
7
+ The main entry point of the application is the :func:`main` which actually delegates all the work to :func:`build_greetings`.
doc/index.rst ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. Template Python project documentation master file, created by
2
+ sphinx-quickstart on Wed Mar 22 15:25:04 2023.
3
+ You can adapt this file completely to your liking, but it should at least
4
+ contain the root `toctree` directive.
5
+
6
+ Welcome to AI playground's documentation!
7
+ ===================================================
8
+
9
+ .. toctree::
10
+ :maxdepth: 2
11
+ :caption: Contents:
12
+
13
+ How to... <howto>
14
+
15
+ API reference <_autosummary/athai>
16
+
17
+ about
18
+
19
+
20
+ Indices and tables
21
+ ==================
22
+
23
+ * :ref:`genindex`
24
+ * :ref:`modindex`
25
+ * :ref:`search`
doc/todo.rst ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ TODO
2
+ ====
3
+
4
+ .. todolist::
jupyter/ReadMe.rst ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ About the Jupytext workflow
2
+ ===========================
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ This directory contains the actual experiments files.
8
+ Typically, these are Jupyter_ notebooks;
9
+ but the ``.ipynb`` format plays especially bad with git version control.
10
+
11
+ The Jupytext_ tool and workflows provide for a workaround to help with
12
+ version-controlled collaboration by pairing the ``.ipynb`` files with
13
+ python scripts (``.py``) or documentation files (``.rst``, ``.md``).
14
+
15
+ Please refer to Jupytext_ documentation or this `JupyterCon 2020 talk`__.
16
+
17
+ __ https://github.com/mwouts/jupytext_jupytercon2020/blob/master/README.md
18
+
19
+ .. _Jupytext: https://jupytext.readthedocs.io/en/latest/index.html#
20
+ .. _Jupyter: https://jupyter.org/
21
+
22
+ Intended workflow
23
+ -----------------
24
+
25
+
26
+ Create new native Jupyter notebooks in the ``experiments/notebook``
27
+ folder or one of its sub-folders and *do not add them to your commit*.
28
+ They will be synchronized automatically by pre-commit hooks with
29
+ Python scripts using the `percent format` stored in ``experiments/script``
30
+ that are much cleaner to version-control and review.
31
+
32
+ .. todo::
33
+ Add an option to version or publish finalized notebooks as HTML.
34
+
35
+ Configuration
36
+ -------------
37
+
38
+ The configuration of the pairing is centralized in the :file:`jupytext.toml`.
39
+
40
+ .. github-only
41
+ This RsT comments block allow the provide bellow references for GitHub
42
+ to display (using standard RsT instead of Sphinx) and whatever is bellow
43
+ will be ignored by Sphinx when including this file.
jupyter/notebooks/SOLID_Musing.ipynb ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "attachments": {},
5
+ "cell_type": "markdown",
6
+ "id": "8d39ce6d",
7
+ "metadata": {},
8
+ "source": [
9
+ "## *Principles* ? What is the point ?"
10
+ ]
11
+ },
12
+ {
13
+ "attachments": {},
14
+ "cell_type": "markdown",
15
+ "id": "c10de8ce",
16
+ "metadata": {},
17
+ "source": [
18
+ "The SOLID principles are:\n",
19
+ "\n",
20
+ "* The **S**ingle-Responsibility Principle (*SRP*)\n",
21
+ "* The **O**pen-Closed Principle (*OCP*)\n",
22
+ "* The **L**iskov Substitution Principle (*LSP*)\n",
23
+ "* The **I**nterface Segregation Principle (*ISP*)\n",
24
+ "* The **D**ependency inversion Principle (*DIP*)\n",
25
+ "\n",
26
+ "These five principles are not a specific ordered list (do this, then that, etc) but a collection of best practices, developed through the decades. They are gathered into an acronym, as a mnemonic vehicle to be remembered, similar to others in computer science, e.g.: *DRY*: Don’t Repeat Yourself; *KISS*: Keep It Small and Simple; as pieces of accumulated wisdom. A little side note, the acronym was created years after these five principles were set together.\n",
27
+ "\n",
28
+ "\n",
29
+ "\n",
30
+ "From https://towardsdatascience.com/solid-coding-in-python-1281392a6a94"
31
+ ]
32
+ },
33
+ {
34
+ "attachments": {},
35
+ "cell_type": "markdown",
36
+ "id": "014fad04",
37
+ "metadata": {},
38
+ "source": [
39
+ "STUPID is an acronym that describes bad practices in Oriented Object Programming:\n",
40
+ "\n",
41
+ "* **S**ingleton\n",
42
+ "* **T**ight Coupling\n",
43
+ "* **U**ntestability\n",
44
+ "* **P**remature Optimization\n",
45
+ "* **I**ndescriptive Naming\n",
46
+ "* **D**uplication\n",
47
+ "\n",
48
+ "from https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/#:~:text=SOLID%20is%20an%20acronym%20that,Liskov%20Substitution%20Principle\n"
49
+ ]
50
+ },
51
+ {
52
+ "attachments": {},
53
+ "cell_type": "markdown",
54
+ "id": "30f034a5",
55
+ "metadata": {},
56
+ "source": [
57
+ "# Loading the package dynamically\n"
58
+ ]
59
+ },
60
+ {
61
+ "cell_type": "code",
62
+ "execution_count": null,
63
+ "id": "98f2f3f8",
64
+ "metadata": {
65
+ "lines_to_next_cell": 2
66
+ },
67
+ "outputs": [],
68
+ "source": [
69
+ "%load_ext autoreload\n",
70
+ "%autoreload 1"
71
+ ]
72
+ },
73
+ {
74
+ "cell_type": "code",
75
+ "execution_count": null,
76
+ "id": "14acf530",
77
+ "metadata": {},
78
+ "outputs": [],
79
+ "source": [
80
+ "%aimport athai.hello"
81
+ ]
82
+ },
83
+ {
84
+ "attachments": {},
85
+ "cell_type": "markdown",
86
+ "id": "f8be4aa9",
87
+ "metadata": {},
88
+ "source": []
89
+ }
90
+ ],
91
+ "metadata": {
92
+ "kernelspec": {
93
+ "display_name": "Python 3 (ipykernel)",
94
+ "language": "python",
95
+ "name": "python3"
96
+ },
97
+ "language_info": {
98
+ "codemirror_mode": {
99
+ "name": "ipython",
100
+ "version": 3
101
+ },
102
+ "file_extension": ".py",
103
+ "mimetype": "text/x-python",
104
+ "name": "python",
105
+ "nbconvert_exporter": "python",
106
+ "pygments_lexer": "ipython3",
107
+ "version": "3.9.16"
108
+ }
109
+ },
110
+ "nbformat": 4,
111
+ "nbformat_minor": 5
112
+ }
jupyter/scripts/SOLID_Musing.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ---
2
+ # jupyter:
3
+ # jupytext:
4
+ # text_representation:
5
+ # extension: .py
6
+ # format_name: percent
7
+ # format_version: '1.3'
8
+ # jupytext_version: 1.14.6
9
+ # kernelspec:
10
+ # display_name: Python 3 (ipykernel)
11
+ # language: python
12
+ # name: python3
13
+ # ---
14
+
15
+ # %% [markdown]
16
+ # ## *Principles* ? What is the point ?
17
+
18
+ # %% [markdown]
19
+ # The SOLID principles are:
20
+ #
21
+ # * The **S**ingle-Responsibility Principle (*SRP*)
22
+ # * The **O**pen-Closed Principle (*OCP*)
23
+ # * The **L**iskov Substitution Principle (*LSP*)
24
+ # * The **I**nterface Segregation Principle (*ISP*)
25
+ # * The **D**ependency inversion Principle (*DIP*)
26
+ #
27
+ # These five principles are not a specific ordered list (do this, then that, etc) but a collection of best practices, developed through the decades. They are gathered into an acronym, as a mnemonic vehicle to be remembered, similar to others in computer science, e.g.: *DRY*: Don’t Repeat Yourself; *KISS*: Keep It Small and Simple; as pieces of accumulated wisdom. A little side note, the acronym was created years after these five principles were set together.
28
+ #
29
+ #
30
+ #
31
+ # From https://towardsdatascience.com/solid-coding-in-python-1281392a6a94
32
+
33
+ # %% [markdown]
34
+ # STUPID is an acronym that describes bad practices in Oriented Object Programming:
35
+ #
36
+ # * **S**ingleton
37
+ # * **T**ight Coupling
38
+ # * **U**ntestability
39
+ # * **P**remature Optimization
40
+ # * **I**ndescriptive Naming
41
+ # * **D**uplication
42
+ #
43
+ # from https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/#:~:text=SOLID%20is%20an%20acronym%20that,Liskov%20Substitution%20Principle
44
+ #
45
+
46
+ # %% [markdown]
47
+ # # Loading the package dynamically
48
+ #
49
+
50
+ # %%
51
+ # %load_ext autoreload
52
+ # %autoreload 1
53
+
54
+
55
+ # %%
56
+ # %aimport athai.hello
57
+
58
+ # %% [markdown]
59
+ #
jupytext.toml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Pair notebooks in subfolders of 'notebooks' to scripts in subfolders of 'scripts'
2
+ formats = "jupyter/notebooks///ipynb,jupyter/scripts///py:percent"
poetry.lock ADDED
The diff for this file is too large to render. See raw diff
 
poetry.toml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ [installer]
2
+ # Temporary workaround : poetry 1.4.1 became stricter with invalid weel
3
+ # This preventing install of jupyter and furo.
4
+ modern-installation = false
pyproject.toml ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.poetry]
2
+ name = "hugging-face-playground"
3
+ version = "0.1.0"
4
+ description = "An example of AI project with some (hopefully) good practices"
5
+ authors = ["Anthony Truchet <anthony.truchet@athai.tech>"]
6
+ readme = "README.md"
7
+
8
+ packages = [
9
+ { include = "athai", from = "src" },
10
+ ]
11
+
12
+ [tool.poetry.scripts]
13
+ hello = "athai.hello:main"
14
+
15
+ [tool.poetry.dependencies]
16
+ python = "^3.10"
17
+ streamlit = "^1.24.0"
18
+ pandas = "^2.0.2"
19
+ numpy = "^1.25.0"
20
+
21
+ [tool.poetry.group.dev.dependencies]
22
+ pre-commit = "^3.2.0"
23
+ commitizen = "^2.42.1"
24
+ flake8-docstrings = "^1.7.0"
25
+ pygments = "^2.14.0"
26
+ huggingface-hub = "^0.15.1"
27
+
28
+ [tool.poetry.group.tests.dependencies]
29
+ pytest = "^7.2.2"
30
+ mockito = "^1.4.0"
31
+ coverage = "^7.2.2"
32
+ xdoctest = "^1.1.1"
33
+
34
+ [tool.poetry.group.doc.dependencies]
35
+ sphinx = "^6.1.3"
36
+ sphinx-autobuild = "^2021.3.14"
37
+ sphinx-rtd-theme = "^1.2.0"
38
+ myst-parser = "^1.0.0"
39
+ darglint = "^1.8.1"
40
+
41
+ [tool.poetry.group.jupyter.dependencies]
42
+ jupyter = "^1.0.0"
43
+ jupytext = "^1.14.5"
44
+
45
+ [tool.pytest.ini_options]
46
+ minversion = "6.0"
47
+ testpaths = ["tests", "src",]
48
+ # Comment out next line to skip running examples section of doc-strings as tests
49
+ addopts = "--xdoctest"
50
+
51
+ [tool.coverage.run]
52
+ branch = true
53
+ source_pkgs = ["athai",]
54
+
55
+ [tool.coverage.report]
56
+ # fail_under = 90
57
+ show_missing = true
58
+
59
+ [tool.isort]
60
+ profile = "black"
61
+ force_single_line = true
62
+ lines_after_imports = 2
63
+
64
+ [tool.black]
65
+ line-length = 79
66
+
67
+ [build-system]
68
+ requires = ["poetry-core"]
69
+ build-backend = "poetry.core.masonry.api"
requirements.txt CHANGED
@@ -1,3 +1,47 @@
1
- streamlit
2
- numpy
3
- pandas
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ altair==5.0.1 ; python_version >= "3.10" and python_version < "4.0"
2
+ attrs==23.1.0 ; python_version >= "3.10" and python_version < "4.0"
3
+ blinker==1.6.2 ; python_version >= "3.10" and python_version < "4.0"
4
+ cachetools==5.3.1 ; python_version >= "3.10" and python_version < "4.0"
5
+ certifi==2023.5.7 ; python_version >= "3.10" and python_version < "4.0"
6
+ charset-normalizer==2.1.1 ; python_version >= "3.10" and python_version < "4.0"
7
+ click==8.1.3 ; python_version >= "3.10" and python_version < "4.0"
8
+ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
9
+ decorator==5.1.1 ; python_version >= "3.10" and python_version < "4.0"
10
+ gitdb==4.0.10 ; python_version >= "3.10" and python_version < "4.0"
11
+ gitpython==3.1.31 ; python_version >= "3.10" and python_version < "4.0"
12
+ idna==3.4 ; python_version >= "3.10" and python_version < "4.0"
13
+ importlib-metadata==6.7.0 ; python_version >= "3.10" and python_version < "4.0"
14
+ jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
15
+ jsonschema==4.17.3 ; python_version >= "3.10" and python_version < "4.0"
16
+ markdown-it-py==2.2.0 ; python_version >= "3.10" and python_version < "4.0"
17
+ markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0"
18
+ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0"
19
+ numpy==1.25.0 ; python_version >= "3.10" and python_version < "4.0"
20
+ packaging==23.1 ; python_version >= "3.10" and python_version < "4.0"
21
+ pandas==2.0.2 ; python_version >= "3.10" and python_version < "4.0"
22
+ pillow==9.5.0 ; python_version >= "3.10" and python_version < "4.0"
23
+ protobuf==4.23.3 ; python_version >= "3.10" and python_version < "4.0"
24
+ pyarrow==12.0.1 ; python_version >= "3.10" and python_version < "4.0"
25
+ pydeck==0.8.0 ; python_version >= "3.10" and python_version < "4.0"
26
+ pygments==2.15.1 ; python_version >= "3.10" and python_version < "4.0"
27
+ pympler==1.0.1 ; python_version >= "3.10" and python_version < "4.0"
28
+ pyrsistent==0.19.3 ; python_version >= "3.10" and python_version < "4.0"
29
+ python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0"
30
+ pytz-deprecation-shim==0.1.0.post0 ; python_version >= "3.10" and python_version < "4.0"
31
+ pytz==2023.3 ; python_version >= "3.10" and python_version < "4.0"
32
+ requests==2.31.0 ; python_version >= "3.10" and python_version < "4.0"
33
+ rich==13.4.2 ; python_version >= "3.10" and python_version < "4.0"
34
+ six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
35
+ smmap==5.0.0 ; python_version >= "3.10" and python_version < "4.0"
36
+ streamlit==1.24.0 ; python_version >= "3.10" and python_version < "4.0"
37
+ tenacity==8.2.2 ; python_version >= "3.10" and python_version < "4.0"
38
+ toml==0.10.2 ; python_version >= "3.10" and python_version < "4.0"
39
+ toolz==0.12.0 ; python_version >= "3.10" and python_version < "4.0"
40
+ tornado==6.3.2 ; python_version >= "3.10" and python_version < "4.0"
41
+ typing-extensions==4.6.3 ; python_version >= "3.10" and python_version < "4.0"
42
+ tzdata==2023.3 ; python_version >= "3.10" and python_version < "4.0"
43
+ tzlocal==4.3.1 ; python_version >= "3.10" and python_version < "4.0"
44
+ urllib3==2.0.3 ; python_version >= "3.10" and python_version < "4.0"
45
+ validators==0.20.0 ; python_version >= "3.10" and python_version < "4.0"
46
+ watchdog==3.0.0 ; python_version >= "3.10" and python_version < "4.0" and platform_system != "Darwin"
47
+ zipp==3.15.0 ; python_version >= "3.10" and python_version < "4.0"
scripts/build-clean-docs.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+
3
+ DOCS_GENERATED_API_SRC=src/athai
4
+ DOCS_SRC=doc
5
+ DOCS_GENERATED_API_DST=doc/_autosummary
6
+ DOCS_DST=dist/doc
7
+
8
+ rm -rf $DOCS_DST
9
+ rm -rf $DOCS_GENERATED_API_DST
10
+
11
+ poetry run sphinx-build -E -a $DOCS_SRC $DOCS_DST
scripts/interactive-rebuild-docs.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #!/usr/bin/env sh
2
+ poetry run sphinx-autobuild --open-browser doc dist/doc
scripts/run-all-precommit-checks.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #!/usr/bin/env sh
2
+ poetry run pre-commit run --all-files --hook-stage=manual
scripts/run-coverage.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/usr/bin/env sh
2
+ poetry run coverage run --parallel -m pytest
3
+ poetry run coverage combine
4
+ poetry run coverage report
scripts/run-tests.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #!/usr/bin/env sh
2
+ poetry run pytest
src/athai/hello.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+
4
+ print(
5
+ f"executing the file '{__file__}'"
6
+ f"in module '{__name__}' and package '{__package__}'"
7
+ )
8
+
9
+
10
+ def build_greetings(name: Optional[str] = None) -> str:
11
+ """
12
+ Return a greeting message, possibly customize with a name.
13
+
14
+ >>> build_greetings()
15
+ 'Hello, World!'
16
+ >>> build_greetings('Toto')
17
+ 'Nice to meet you, Toto!'
18
+ """
19
+ return name and f"Nice to meet you, {name}!" or "Hello, World!"
20
+
21
+
22
+ def main():
23
+ print(build_greetings())
24
+
25
+
26
+ if __name__ == "__main__":
27
+ main() # pragma: no cover
tests/athai/test_hello.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from athai import hello
2
+
3
+
4
+ def test_hello_default():
5
+ assert hello.build_greetings() == "Hello, World!"
6
+
7
+
8
+ def test_hello_name():
9
+ assert hello.build_greetings("Toto") == "Nice to meet you, Toto!"
10
+
11
+
12
+ # Given / Arrange
13
+ # When / Act
14
+ # Then / Assert
tests/conftest.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # conftest.py
2
+ import pytest
3
+
4
+
5
+ @pytest.fixture
6
+ def unstub():
7
+ """Ensure calls patched by mockito are cleared after each test"""
8
+ from mockito import unstub
9
+
10
+ yield
11
+ unstub()