commit c8682d48012986d2716e93f0c9cb3fc0e4e861fa Author: Steve Kossouho Date: Fri Jul 4 19:26:39 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..807c92a --- /dev/null +++ b/.gitignore @@ -0,0 +1,166 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +/documentation/slides/ +.idea diff --git a/documentation/00-course-plan.adoc b/documentation/00-course-plan.adoc new file mode 100644 index 0000000..9d71e77 --- /dev/null +++ b/documentation/00-course-plan.adoc @@ -0,0 +1,180 @@ +— +title: Plan de formation Python Initiation +author: Steve Kossouho + +''' + += Programme de Python Initiation + +''' + +La formation s'adresse à des quasi débutants en programmation, ou curieux d'en savoir un peu plus sur les bases de Python. +Pour les plus avancés, le rythme change (uniquement si le groupe est suffisamment homogène). + +''' + +== Démarrage + +* Tour de table et présentation +* Logistique, planning et administratif +* Rappel du programme + +''' + +== Découvrir Python + +* Nature de Python et court historique +* Versions de Python et différences +* Découvrir la ligne de commande et le shell +* Environnements de développement intégrés +* Créer un nouveau projet avec PyCharm + +`lundi 10h30 si pas de pb d'install` + +''' + +== Découvrir le langage + +* Syntaxe de base +* Types de base : chaînes, nombres +* Variables et expressions +* Contrôler ce que l'on exécute : conditions et boucles +* Découvrir les listes (et tuples, sets) + slicing +* Découvrir les dictionnaires +* Compréhensions (listes etc.) +* Opérations sur les chaînes : méthodes et formatage + +`mardi 14h30 max` + +''' + +== Le droit aux erreurs + +* Découvrir le concept d'exceptions + +`mardi 15h45` + +''' + +== Découvrir les fonctions + +* Découvrir l'utilité des fonctions +* Découvrir la syntaxe +* Référence vs appel de fonction +* Valeurs de retour d'une fonction +* Passer des arguments aux fonctions + +`mercredi 10h00` + +''' + +== Découvrir la structure du code au-delà du simple script + +* Expliquer ce qu'est pip, venv (avec exemples) et aussi conda +* Modules et packages +* Bibliothèque standard python et imports +* Exemple : faire un peu de calcul avec la bibliothèque standard +* Réutiliser votre propre code +* Extra : virtualenv et pip) + +`mercredi 12h00` + +''' + +== Types supplémentaires + +* Découvrir les types heure+date et intervalle de temps +* Convertir depuis du texte ou vers du texte + +`mercredi 14h30` + +''' + +== Découvrir la programmation orientée objet + +* Intérêts de la programmation objet +* Découvrir la syntaxe +* Concepts d'attributs et de méthodes +* Différence entre une classe et ses objets +* Instancier avec une autre signature +* Découvrir l'héritage et le polymorphisme +* Bonus : Courte introduction aux décorateurs avec @staticmethod +* Bonus : Introspection (getattr, setattr, dir, isinstance, type) +* Bonus : Diagramme de classes UML + +`mercredi 17h00` + +''' + += Programme de Python Approfondissement + +Même public que l'initiation : peu d'expérience en programmation ou curiosité quant à Python. Nécessite toutefois de connaître les bases du langage. + +*Objectif* : aller un peu plus loin dans les bases de Python pour pouvoir traiter quelques données. + +''' + +== Découvrir comment manipuler des fichiers texte + +* Écrire et lire des fichiers (open/close) +* Écrire et lire des fichiers (gestionnaire de contexte) +* Formats : JSON +* Formats : CSV +* Extra : Parcours de fichiers (pathlib) + +`jeudi 14h30` + +''' + +== Toucher du doigt les bases de données SQL avec DBAPI et SQLite3 + +* Exemple simple pour dialoguer avec une base SQL +* Ajouter et requêter des données simplement +* Bonus : ORMs (peewee) + +`jeudi 17h00` + +''' + +== Documenter du code Python + +* Comment on fait ? +* Qu'est-ce qu'on documente ? +* Comment on génère des fichiers HTML de documentation ? (pdoc3, sphinx) +* Bonus : Donner des indications sur le type des variables et arguments + +`vendredi 10h45` + +''' + +== Faire sa première interface graphique avec Python + +* Exemples d'outils pour les interfaces graphiques +* PySide6 avec Python (sous Linux) +* Écrire une fenêtre simple +* Interagir avec les contrôles (boutons, champs) +* Concevoir graphiquement une fenêtre et l'utiliser avec Python + +`vendredi 15h45` + +''' + +== Bonus : Aborder la journalisation + +* Qu'est-ce que c'est ? Et pourquoi, pour qui, quand ? +* Exemple simple de journalisation +* Exemple configuré de journalisation dans un fichier + +`vendredi 16h30` (selon possibilités) + +''' + +== Certifications + +Au plus tard le vendredi à 15h30. Dure jusqu'à 17h30. + +''' + +== That's all folks! + +image:assets/images/x-outro-end.png[That's all folks!] diff --git a/documentation/01-discover.md b/documentation/01-discover.md new file mode 100644 index 0000000..8888169 --- /dev/null +++ b/documentation/01-discover.md @@ -0,0 +1,168 @@ +--- +title: Découvrir Python +author: Steve Kossouho +--- + +[intro-guido]: assets/images/intro-guido.jpg +[intro-terminal]: assets/images/intro-terminal.png +[ide-pycharm]: assets/images/ide-pycharm.png + +# Découvrir Python + +---- + +## Introduction à Python + +Python, c'est surtout : + +- Un langage de programmation généraliste +- Bénéficie de 33 ans d'améliorations publiques (fév. 1991) +- Très populaire depuis 2018 +- Et il paraît que c'est simple à apprendre… + +---- + +### Popularité 2021 + +![Popularité des langages de programmation 2021](assets/images/x-intro-tiobe-2021.jpg) + +---- + +### Popularité 2022 + +![Popularité des langages de programmation 2022](assets/images/x-intro-tiobe-2022.png) + +---- + +## Historique de Python + +- Développement débuté en décembre 1989 par **Guido Van Rossum** +- Première publication le 20 février 1991 (version 0.9) +- Maintenu par la **Python Software Foundation** (mars 2001) +- Licence permissive (PSFL) similaire à la BSD +- Utilisé en éducation, IA, traitement de données, automatisme etc. +- Python 2.0 sorti en octobre 2000 : gestion Unicode +- Python 3.0 (Python 3000) sorti en décembre 2008 : réorganisation +- Python 3.11 sorti en novembre 2022 : performance + +---- + + ![Guido Van Rossum, BDFL jusqu'en 2018][intro-guido] + +---- + +![Équipe des développeurs de Python en 2018](assets/images/x-intro-core-developers-2018.jpg) + +---- + +## Propriétés techniques de Python + +Le langage Python repose sur le socle technique suivant : + +- Langage **interprété** : un programme exécute vos scripts +- Langage de programmation impérative : instructions exécutées dans l'ordre +- Langage de programmation fonctionnelle +- Langage de programmation strictement orienté objet (différent de Java) +- Typage dynamique des variables +- Syntaxe relativement concise +- Démarrage facile (davantage que Java, C, Rust…) + +---- + +### Python 3.x + +- Première version (Python 3000) datée du 3 décembre 2008 +- Version prise en charge la plus ancienne : _3.7_ (2018) +- Version la plus récente stable : _3.11_ (2022) +- Version la plus répandue (Linux) : _3.9_ + + +---- + +## Démarrer avec Python sous Linux + +Les machines Linux proposent toujours un terminal, même si vous y travaillez via une interface de bureau graphique (Gnome, KDE ou autre). +L'environnement de développement intégré graphique **PyCharm** en inclut également un. + +Sous Windows, l'invite de commande ou **PowerShell** sont également des terminaux. On conseillera +largement PowerShell face à `cmd.exe`. Pour cette raison, passez à Windows 10 au minimum. + +---- + +### Terminaux sous Linux + +![Neofetch lancé dans le Terminal de Gnome][intro-terminal] + +---- + +### Environnements de développement + +Il existe de nombreux éditeurs de code et environnements intégrés de développement. Entre autres : + +1. PyCharm (Community ou Professional) +2. Visual Studio Code +3. Spyder +4. ~~Atom~~ + +Les environnements de développement vous facilitent l'écriture et l'exécution de code en Python, +même si vous pourriez également tout faire avec un terminal et un éditeur de texte. + +**Note** : Si vous possédez une adresse email académique (ex. université), vous avez normalement +accès [gratuitement à PyCharm Professional](https://www.jetbrains.com/fr-fr/community/education/#students) +(intégration Jupyter, Numpy et Pandas, profiling, Django et Javascript, Frameworks JS, Docker etc.) + +---- + +#### PyCharm + +PyCharm, développé par JetBrains (CZ), est un environnement de développement intégré spécialisé +dans la programmation Python. Il existe dans deux versions, **Community** (gratuite) et **Professional**, +cette dernière prenant en charge les bases de données, les frameworks web, le profiling et l'analyse de données etc. + +Points particuliers : + +- Excellente prise en charge du langage +- Interface élégante et personnalisable +- Débogueur intégré +- Console Python avancée +- Terminal efficace et fonctionnel +- Système de plugins offrant de nouvelles fonctionnalités + +---- + +#### Visual Studio Code + +Visual Studio Code est développé par Microsoft (US). C'est un environnement de développement généraliste +qui fonctionne avec des extensions pour augmenter ses capacités. Il est totalement gratuit et très utilisé +par les développeurs Python ayant débuté en 2017 et au-delà. + +Points particuliers : + +- Lancement rapide +- Couleurs personnalisables et zoom +- Beaucoup d'extensions pour beaucoup de fonctions +- Bon support du langage +- Expérience utilisateur limitée par l'interface + +---- + +#### Spyder + +Spyder a été développé par Pierre Raybaut (FR). C'est un éditeur de code Python simple et spécialisé +dans l'exécution de petits scripts, notamment pour les chercheurs et académiciens. + +Points particuliers : + +- Interface simple +- Visualisation des variables dans un tableau à l'exécution +- Aucune notion de projet +- Pas de terminal intégré + +---- + +### Créer un projet avec PyCharm + +1. Lancer PyCharm et créer un nouveau projet +2. Choisir le nom du répertoire de projet +3. Choisir le nom du répertoire d'isolation de dépendances (`virtualenv`) +4. C'est parti ! diff --git a/documentation/02-language-basics-data.md b/documentation/02-language-basics-data.md new file mode 100644 index 0000000..65c4587 --- /dev/null +++ b/documentation/02-language-basics-data.md @@ -0,0 +1,493 @@ +--- +title: Découvrir le langage - types de données avancés +author: Steve Kossouho +--- + +# Collections de données + +---- + +## Les listes + +Type de collection de données : `list`{.python}. Une liste peut contenir une **séquence** d'éléments +de n'importe quel type pris en charge par Python, y compris d'autres listes. Le contenu d'une liste est modifiable (ajouter, retirer des éléments…) + +```python {.numberLines} +liste1 = [1, 2, 3, 4, 5, 6] # types cohérents +liste2 = [1, 2, 3, "a", "b", "c"] # types divers +liste3 = [None, None, True, False] +liste4 = [[1, 2, 3], [4, 5, 6]] +liste5 = [] # liste vide, équivalent à list() +liste6 = [liste1] # Liste contenant 1 élément, qui est lui-même une liste +``` + +---- + +Il est possible de manipuler une liste facilement. On peut ajouter des éléments à la fin, à une +position précise, retirer un élément ou encore récupérer un élément seul. + +```python {.numberLines} +liste1 = [1, 2, 3, 4, 5, 6] +liste2 = list() # Créer une nouvelle liste vide + +# Infos sur la liste +length = len(liste1) # Récupérer le nombre d'éléments +position = liste1.index(3) # Renvoie l'index de la valeur 3, ou erreur si introuvable +nine_trouvable = 9 in liste1 # Renvoie si l'élément 9 existe dans la liste +# Récupérer des éléments +print(liste1[0]) # Affiche le premier élément si la liste est non vide +# Manipuler le contenu +liste1.append(7) # Ajoute 7 comme nouvel élément à la fin +liste1.insert(0, 99) # Insère 99 comme nouvel élément au tout début +liste1[0] = 98 # Remplace la valeur à l'index 0 +liste1.remove(4) # Enlève la première occurrence du nombre 4, ou erreur si introuvable +del liste1[3] # Retire l'élément à l'index 3 +``` + +[Méthodes accessibles sur les listes](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) + +---- + +### Erreurs d'accès + +Accéder à un élément de liste n'existant pas génère une erreur (`IndexError`{.python}) et interrompt +votre programme; il peut être utile d'utiliser la fonction `len()`{.python} pour tester que vous +accédez à un indice valide. + +```python {.numberLines} +liste1 = [1, 2, 3] +if len(liste1) >= 4: + print(liste1[3]) +``` + +---- + +### Erreurs de méthodes + +La méthode `.remove(valeur)`{.python} provoque également une erreur (`ValueError`{.python}) si +l'élément en argument n'existe pas dans la liste. De la même façon, il peut être utile de tester +qu'un élément est présent dans la liste avant d'essayer de l'en supprimer : + +```python {.numberLines} +liste1 = [1, 2, 3] +if 8 in liste1: + liste1.remove(8) +``` + +---- + +### Indices de liste négatifs + +Il est également possible d'accéder à des éléments de liste en utilisant des indices négatifs. + +Si la liste n'est pas vide, l'élément d'indice `-1` est le dernier élément de la liste (équivalent +à `len(liste) - 1`{.python}), et l'élément à l'indice `-len(liste)`{.python} est le premier ( +équivalent à `0`). + +Tout nombre inférieur génère une erreur de type `IndexError`{.python}. + +```python {.numberLines} +liste1 = [1, 2, 4, 6, 9, 11] +print(liste1[-1]) +``` + +---- + +## Parcourir une liste + +Comme on l'a vu avec la boucle `for`{.python}, utilisée avec `range()`{.python}, on peut utiliser la +boucle `for`{.python} sur une liste : + +```python {.numberLines} +prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31] +for number in prime_numbers: + print(number) +``` + +La variable `number`{.python} déclarée pour la boucle contiendra tour à tour +les valeurs `2`{.python}, puis `3`{.python}, puis `5`{.python}, etc. + + +---- + +## Opérations sur listes + +Récupérer des portions ou partitions de listes (slicing) : + +```python {.numberLines} +a = [10, 15, 20, 25, 30, 35, 40, 45, 50, 55] +b = a[0:5] # Index 0 à 5 non inclus. Marche aussi sur les chaînes. +c = a[5:0] # L'index de fin est inférieur au départ, renvoie une liste vide +d = a[:] # Renvoie une copie de toute la liste +e = a[::-1] # Tout parcourir à l'envers +f = a[::2] # Tout parcourir 2 par 2 +g = a[5:2:-1] # L'indice de début est supérieur à l'indice de fin +h = a[2:5:-1] # Le pas est négatif, start < end, renvoie une liste vide +``` + +Pourquoi créer des portions de listes ? Cela peut-être utile, par exemple, si +vous souhaitez appliquer un calcul sur une petite partition d'un jeu de données. + +---- + +## Autres collections + +Outre les listes, il existe 3 types de base pour collectionner des éléments : + +- Tuple : `tuple()`{.python} +- Set (jeu d'éléments uniques) : `set()`{.python} +- Dictionnaires (association) : `dict()`{.python} + +---- + +### Tuples + +**Tuple** : Un `tuple`{.python} fonctionne quasiment trait pour trait comme une liste, à la différence qu'une +fois que vous avez défini ses éléments, vous ne pouvez plus en changer. On parle de « collection immuable ». + +```python {.numberLines} +a = (1, 2, 3) +b = () # ou tuple() +c = (1,) # il vous faut au minimum une virgule +d = (None, "Salut", 15, 2.718) +``` + +Les méthodes de modification de contenu, telles que `append`{.python} etc. ne sont logiquement pas disponibles avec +ce type : [opérations des tuples](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) + +---- + +### Ensembles (données uniques) + +**Set** (ensemble) : Un `set`{.python} peut contenir plusieurs éléments et est modifiable au même titre +qu'une liste, mais n'est pas une séquence; aucune notion d'ordre ou d'index. +La collection garantit l'unicité des éléments, un élément ne pouvant apparaître qu'une fois au maximum +dans votre objet. + +```python {.numberLines} +a = {1, 1, 2, 3, 3, 3} # équivaut à {1, 2, 3}, les valeurs étant uniques à la fin +b = {2, 4, 5, "hello", (1, 2, 3)} +c = set() # obligatoire pour déclarer un set vide, sinon considéré dict +print(len(b)) +a.add(9.5) # ajoute la valeur 9.5 (float) au set +a.discard(9.5) # retire la valeur 9.5, ou ne fait rien +d = a.intersection(b) # renvoie un set avec les éléments communs à a et b +e = a.union(b) # avec les éléments présents dans a ou b +... +``` + +[Méthodes disponibles sur les ensembles](https://docs.python.org/fr/3/library/stdtypes.html#set) + +---- + +![Opérations sur les ensembles](assets/images/basics-sets-operations.jpg) + +---- + +#### Bonus : Particularités des ensembles + +Les ensembles sont des structures de données très efficaces. Techniquement, vous pouvez attendre une +complexité en `O(1)` pour que Python sache si un élément est déjà présent ou pas; cela signifie qu'il +faut plus ou moins le même nombre d'opérations pour trouver un élément, que votre `set`{.python} en possède un +seul ou un milliard. + +L'algorithme et la structure de données interne à Python derrière cette efficacité se nomme **Table de hachage**. + +---- + +##### Tables de hachage + +Une table de hachage fonctionne en trois temps : + +- On réserve des zones de mémoire d'avance (**buckets**), au départ vides; +- lorsque l'on souhaite vérifier si un élément y est présent, on lui calcule une signature (`hash()`{.python}); +- la signature de l'objet permet de savoir quelle zone de mémoire consulter pour le trouver. +- si la zone de mémoire est vide, c'est que l'objet n'était pas présent. + +---- + +##### Exemple de hachage + +![Table de hachage](assets/images/basics-sets-hashing.png) + +---- + +##### Hachage + +La signature est un nombre calculé qui est sensé dépendre du contenu d'un objet. Python propose une fonction +à cet effet, `hash()`{.python}, pour laquelle chaque classe propose sa propre implémentation. +L'objectif d'un hash est simple; deux objets différents doivent avoir un hash différent. +Dans Python ce dernier est un nombre entier sur 64 bits. Si deux objets a et b ont le même hash, ils seront généralement +considérés comme équivalents et donc en **collision** (dans ce cas, `a == b`{.python}). S'ils ne sont pas considérés équivalents, +il n'y a pas de collision. + +---- + +##### Hachage en général dans Python + +Entre deux lancements d'un interpréteur Python, le hash de la majorité des objets est différent; +l'algorithme utilise une valeur aléatoire pour générer les hashs, de façon qu'il soit impossible de créer un +dictionnaire de signatures dédié à créer des collisions. + +Le hachage est en général imprévisible pour les valeurs suivantes : + +- `str`{.python} non vides +- `float`{.python} non équivalents à un `int`{.python} +- `None`{.python} +- `tuple`{.python} + +---- + +##### Hashes prévisibles + +Le hash est par contre prévisible pour les valeurs suivantes : + +- `0`{.python}, `0.0`{.python}, `False`{.python} et `""`{.python} ont un hash de `0`{.python} mais `""`{.python} n'est pas équivalent; +- `1`{.python}, `1.0`{.python} et `True`{.python} ont un hash de `1`{.python} et sont tous en collision. +- `int`{.python}, où le hash est identique au nombre... + +Les objets `int`{.python} ont généralement un `hash()`{.python} identique, sauf cas suivants : + +- `-1`{.python} a un hash de `-2`{.python} car la valeur `-1`{.python} est un code d'erreur; +- `2 ** 61 - 2`{.python} est le dernier nombre positif avec un hash identique; +- à partir de `2 ** 61 - 1`{.python}, le hash revient à 0 etc. +- le même algorithme fonction sur les entiers négatifs, mais avec des hashes négatifs. + +---- + +##### Hashes impossibles + +L'algorithme de la table de hachage nécessite qu'un objet stocké dans un bucket possède en +permanence un `hash` correspondant à son bucket. Cela pose un problème avec les objets modifiables +à tout moment, tels que les `list`{.python}, `set`{.python} ou encore les `dict`{.python}. + +La solution adoptée par Python consiste à interdire le calcul de signature desdits objets. +Les `tuple`{.python} demeurent des données valides, puisque nous avons la garantie de ne jamais pouvoir +changer leur contenu, et ainsi leur signature. + +```python {.numberLines} +# La fonction hash est disponible par défaut en Python +print(hash([1, 2, 3])) # Provoque une exception +``` + +---- + +### Dictionnaires : associations entre clés et valeurs + +**Dictionnaires** : (`dict`{.python}) C'est un **ensemble** d'associations où l'on définit clés et valeurs. C'est le même +fonctionnement qu'un dictionnaire lexicographique, où, lorsque vous avez le +mot (la clé), vous retrouvez la définition s'il y en a une (la valeur). D'autres langages ont des structures +similaires et appellent ça des `HashMap`{.java} ou des `object`{.javascript}. + +```python {.numberLines} +a = {"server1": "192.168.1.2", "server2": "192.168.1.3", "server3": "192.168.1.5"} # serveurs et adresses IP +b = {8: "Mme Garnier", 10: "M. Dubois", 11: "Mlle Yousfi", 12: "Mme Préjean"} # rendez-vous horaires +d = {1.2: "flottant", True: "booléen", None: "rien", (1, 2, 3): "tuple"} # clés de plusieurs types +c = {} # ou dict(), ceci est un dictionnaire vide +print(a["server1"]) # affiche "192.168.1.2" +print(b[10]) # affiche "M. Dubois" +print(b[9]) # provoque une erreur +``` + +---- + +#### Parcourir un dictionnaire + +Il est possible de parcourir un dictionnaire avec une boucle `for`{.python}. De base, ce sont les +clés du dictionnaire qui sont parcourues. Mais il existe des variantes assez pratiques pour +parcourir un dictionnaire : + +```python {.numberLines} +a = { + "Jérémy": (25, "M", "Lille"), + "Hélène": (30, "F", "Ambérieu-en-Bugey"), + "Gwladys": (35, "F", "Nyons"), +} + +for prenom in a: + print(prenom) # affiche uniquement une clé + print(a[prenom]) # retrouve la valeur associée à la clé +``` + +---- + +Si vous parcourez une collection dont tous les éléments sont eux-mêmes des séquences +de `n` éléments, vous pouvez les dépaqueter (**unpacking**) : + +```python {.numberLines} +# Avancé, unpacking via la méthode `items` + +for item in a.items(): # a.items() renvoie ((clé1, valeur1), (clé2, valeur2), …) + print(item) # est un tuple + +for key, value in a.items(): + # on peut utiliser 2 variables de boucle si chaque élément parcouru est + # une séquence de taille 2. Merci l'unpacking ! + print(key, value) +``` + +---- + +#### Manipuler un dictionnaire + +Pour changer la valeur associée à une clé existante, ou par la même occasion, associer une valeur à +une nouvelle clé, il suffit d'écrire : + +```python {.numberLines} +a = {"Bordeaux": 250000} +a["Marseille"] = 800000 +a["Bordeaux"] = 90 +print(a["Bordeaux"]) # Affiche 90 +# On peut supprimer du dictionnaire une association en écrivant +del a["Marseille"] # plus de clé pour Marseille ! +print("Marseille" in a) # renvoie si la clé "Marseille" existe +``` + +---- + +### Plus : méthodes de dictionnaires + +La méthode `get(key, default)`{.python} des dictionnaires renvoie la valeur associée à une clé. Si +l'on ne passe pas de valeur pour l'argument `default`{.python}, pour une clé introuvable, la méthode +renvoie `None`{.python} (au lieu de planter comme lorsqu'on écrit `dict[key]`{.python}). + +```python {.numberLines} +populations = {"Paris": 2.6e6, "Marseille": 8e5, "Lyon": 5e5, "Bordeaux": 2.5e5} +print(populations.get("Tarbes")) # renvoie None +print(populations.get("Mulhouse", -1)) # renvoie -1 +print(populations.get("Marseille", -1)) # renvoie 800 000.0 +``` + +Si l'on passe une valeur pour l'argument `default`{.python}, alors, si la clé n'a pas été trouvée, +la méthode renvoie la valeur de repli que vous avez définie. + +---- + +## Compréhensions de listes, tuples etc. + +Déclarer des listes, tuples, sets et dictionnaires avec la syntaxe de compréhension : + +```python {.numberLines} +a = [x * 2 for x in range(100)] # tous les nombres pairs de 0 à 198 +b = [x * 2 for x in range(100) if x != 10] # nombres pairs de 0 à 198 sauf 20 +c = (x for x in range(100)) # pas un tuple mais un générateur, nombres de 0 à 99 +d = {x / 2 for x in range(100)} # on peut faire pareil avec les sets +pre = {"Jon": None, "Pam": None, "Mel": None, "Kim": None} +e = {k: pre[k] for k in pre} # on copie pre +``` + +---- + +## Récapitulatif des collections + +| Type | Propriétés | +|---------------|--------------------------------------------------------------------------------------------------------------------------| +| `list` | `[...,]`{.python}. Séquence dont le contenu est modifiable (ajout, suppression). | +| `tuple` | `(...,)`{.python}. Séquence dont le contenu est gelé après déclaration. Utilisable comme élément d'un `set`. | +| `set` | `{...,}`{.python}. Déduplique les éléments et permet des opérations entre ensembles
(union, intersection etc.) | +| `dict` | `{..:..,}`{.python}. Structure de **recherche** rapide où l'on peut associer des valeurs quelconques à des identifiants. | + +---- + +### Usages d'exemple + +Le `tuple`{.python} n'est jamais très important, et il sera souvent plus pratique de travailler sur des listes. Les seuls +cas de figure qui obligent à utiliser des `tuple`{.python} sont les cas où vous voulez ajouter une séquence comme élément d'un `set` +ou comme clé d'un `dict`{.python}. + +- `list`{.python} : si vous avez des données séquentielles à stocker, par exemple lues depuis un fichier. +- `set`{.python} : si vous souhaitez enlever des doublons, connaître le nombre d'éléments uniques. +- `dict`{.python} : si vous avez besoin d'une "table de référence" pour stocker des données que vous allez rechercher fréquemment. + +---- + +# Chaînes de caractères + +---- + +## Opérations sur les chaînes de caractères + +Nous n'avons pas vu grand chose sur les chaînes de caractères, mais certaines informations peuvent +être fréquemment utiles aux développeurs : + +- [Méthodes sur les objets de type `str`{.python}](https://docs.python.org/3/library/stdtypes.html#string-methods) +- [Formatage de chaînes via les f-strings](https://zetcode.com/python/fstring/) +- [Documentation officielle sur le format des interpolations](https://docs.python.org/3/library/string.html#format-string-syntax) + +```python {.numberLines} +a = 19 +b = f"Le serveur qui doit être vérifié aujourd'hui est le numéro {a}" +c = f"Formatage de la variable : {a:f}" # affiché comme flottant (6 chiffres après la virgule) +``` + +---- + +## Les chaînes de caractères et leurs méthodes + +```python {.numberLines} +chaine = "Bonjour" +print(chaine.upper(), chaine.lower()) +print(chaine.center(50, " ")) # Centre la chaîne originale sur 50 caractères +``` + +Méthodes qui renvoient une copie modifiée d'une chaîne + +---- + +## Méthodes fréquemment utiles sur les chaînes de caractères + +- `upper()`{.python} : renvoie une copie en majuscules +- `lower()`{.python} : renvoie une copie en minuscules +- `strip()`{.python} : retire les espaces aux extrêmités +- `replace(old, new, count=None)`{.python} : remplace `old` par `new` +- `index(sub, start=None)`{.python} : renvoie la position de `sub` +- `sub in text`{.python} : renvoie si `sub` est inclus dans `text` +- `split(sep=None)`{.python} : découpe en liste autour du séparateur, par défaut autour des espaces +- `str.join(iterable)`{.python} : sert de séparateur et joint une liste de chaînes + +---- + +```python {.numberLines} +chaine = "Bonjour, nous sommes le 17 juillet 2063." +words = chaine.split() # renvoie une liste de chaînes autour des espaces +rejoin = " ".join(words) # renvoie une chaîne en insérant l'espace comme séparateur +print(chaine.upper(), chaine.lower(), rejoin) +print("17 juillet" in chaine) +``` + +Exemple de `str.split()`{.python} et `str.join()`{.python} + +---- + +## Bonus : Convertir des données d'un type à un autre + +Nous avons vu, ici et là, quelques fonctions pour déclarer des valeurs de base, ou convertir des +valeurs. En voici une liste plus complète : + +- `bool(val)`{.python} +- `int(val)`{.python}, `float(val)`{.python} +- `str(val)`{.python} +- `list(val)`{.python}, `tuple(val)`{.python} +- `set(val)`{.python}, `dict(val)`{.python} + +Toutes ces fonctions renvoient un nouveau booléen, entier, flottant etc. correspondant à une +conversion de l'expression passée en argument. Cela fonctionne uniquement lorsque la conversion a du sens. + +---- + +Appelées sans argument, ces fonctions vous renvoient `False`{.python}, `0`{.python}, une chaîne ou une +collection vide (des valeurs considérées neutres, qui renvoient toujours `False`{.python} lorsqu'on les convertit en booléen). + +Lorsque vous passez un argument à ces fonctions, elles vous renvoient une nouvelle valeur, +qui est une conversion de l'argument passé vers le type +représenté par la fonction. Ce n'est pas toujours possible d'effectuer une conversion; par exemple, il est impossible de +convertir une liste vers un nombre flottant, ou encore de convertir la chaîne `"bonjour"`{.python} vers un nombre entier. + +```python {.numberLines} +converted1 = int(3.14159) # tronque le flottant / retire la partie décimale +converted3 = float("3.14159") # comprend le texte et génère un flottant +converted2 = list(1) # erreur +converted4 = float("salut") # aucun caractère valide pour représenter un nombre, échoue +``` + + diff --git a/documentation/02-language-basics.md b/documentation/02-language-basics.md new file mode 100644 index 0000000..565480b --- /dev/null +++ b/documentation/02-language-basics.md @@ -0,0 +1,579 @@ +--- +title: Decouvrir le langage +author: Steve Kossouho +--- + +# Bases du langage + +---- + +## Le langage Python + +Le langage Python peut être découpé en deux grands types d'instructions : + +- Les déclarations +- Les expressions + +Les déclarations sont en général des instructions pour créer des variables ou des structures de données. + +Les expressions sont des instructions pour effectuer des calculs ou récupérer des données. + +---- + +## Hello World + +```python {.numberLines} +print("Hello world!") +``` + +---- + +## Commentaires + +En Python, un commentaire est un élément textuel dans votre code qui sera ignoré à l'exécution. +Il ne pourra pas causer d'erreur de syntaxe, mais encore faut-il l'utiliser correctement : + +```python {.numberLines} +# Commentaire sur sa propre ligne +print("Bonjour") # Commentaire à la fin d'une ligne de code +``` + +---- + +## Variables + +Une variable est une boîte en mémoire à laquelle on donne un nom, et dans cette boîte, on place une valeur. +Cette valeur peut être un peu n'importe quoi en Python, mais notamment : + +- Un nombre (entier ou flottant) +- Une chaîne de caractères (texte) +- D'autres types avancés (collection, date, heure, classes, etc.) + +---- + +## Exemple d'assignation de variables + +```python {.numberLines} +a = 15 # Python comprend qu'il s'agit d'un entier +c = 3.14159265358979323 # Python comprend qu'il s'agit d'un flottant +b = "Bonjour" # Python reconnaît du texte +d = input("Entrez du texte") +del c # Détruit la variable, qui devient invalide +``` + +**Note** : une chaîne de caractères peut aussi être marquée par le caractère `'` : + +```python {.numberLines} +b = 'Bonjour' # Python reconnaît du texte +``` + +---- + +## Changer la valeur associée à une variable + +Une variable a, comme son nom l'indique, la capacité de changer de valeur dans le temps. + +En Python, on utilise exactement la même syntaxe pour déclarer une nouvelle variable ou encore +changer la valeur qui lui est associée : + +```python {.numberLines} +a = 15 +print(a) # Affiche 15 +a = 99 +print(a) # Affiche 99 +a = a + 1 # ou a += 1 +print(a) # Affiche 100 +a = "Bonjour" # On associe une valeur d'un type différent +print(a) # Affiche le texte "Bonjour" +``` + +---- + +## Typographie des variables + +Typographie conventionnelle des noms de variables : + +- Tout en minuscules (ex. `texte`, `tour_eiffel`) +- Commence par une lettre (obligatoire, ex. `saisie`) +- Contient des underscores entre les mots (ex. `user_name`) +- Pas d'accent ni d'espace ni de tiret +- Peut contenir un chiffre, mais pas en premier caractère (ex. `mambo_number_5`) + +---- + +## Expressions + +Une expression correspond toujours à une valeur que l'on pourrait mettre dans une variable. + +```python {.numberLines} +a = 15 +chaine = "bonjour" +nombre = 15 +print(a) # `a` existe et peut être utilisée comme expression +beau_temps = True # Valeur spécifique *vrai* +sale_temps = False # Valeur spécifique *faux* +non_defini = None # valeur spéciale considérée comme "pas de valeur". +``` + +---- + +## Types de données + +En programmation, les types de données ont des noms, et en Python ce sont les suivants : + +- `int`{.python} : (integer) nombres entiers +- `float`{.python} : (floating point numbers) nombres à virgule flottante +- `str`{.python} : (string) chaînes de caractères +- `bool`{.python} : (boolean) c'est vrai / c'est faux + +```python {.numberLines} +print(type(15)) # Affiche +print(type(15.0)) # Affiche +print(type("Bonjour")) # Affiche +``` + +---- + +## Expressions et opérateurs + +Il est pratique de pouvoir écrire des expressions simples, mais c'est mieux de pouvoir faire des +calculs avec. Il existe des opérateurs mathématiques, mais aussi de comparaison etc. + +```python {.numberLines} +a = 15 +chaine = "bonjour " + "les amis" # intuitif +produit = 15 * 60 # intuitif aussi +a_double = a * 2 # ça aussi +``` + +Exemples d'opérateurs : `+`{.python}, `>`{.python}, `**`{.python}, `%`{.python}, `and`{.python}, +`&`{.python}, `|`{.python}, `^`{.python}, `is`{.python}, `in`{.python}... + +---- + +### Opérateurs arithmétiques + +- Arithmétiques : `+`{.python}, `-`{.python}, `*`{.python}, `/`{.python} +- Modulo : `%`{.python} (reste de la division entière) +- Division entière : `//`{.python} +- Exposant : `**`{.python} (ex. `2 ** 3 == 8`{.python}) + +---- + +### Opérateurs de comparaison + +- `>`{.python}, `<`{.python}, `>=`{.python}, `<=`{.python} +- `==`{.python} (équivalent), `!=`{.python} (non équivalent) + +---- + +### Opérateurs booléens en langage naturel + +- `a and b`{.python} : Vaut `True`{.python} si `a` **et** `b` valent `True`{.python}, sinon `False`. +- `a or b`{.python} : Vaut `True`{.python} si `a` **ou** `b` vaut `True`{.python}, sinon `False`. +- `a in b`{.python} : `True`{.python} si `a` fait partie de la collection ou séquence `b`. +- `a not in b`{.python} : `True`{.python} si `a` ne fait pas partie de la collection ou séquence `b` + . +- `a is b`{.python} : `True`{.python} si `a` est la même référence que `b`. Utilisé avec les booléens + et `None`{.python} notamment. +- `a is not b`{.python} : `True`{.python} si `a` n'est pas la même référence que `b`. +- `not a`{.python} : Convertit `a` en booléen, et renvoie la valeur opposée. + +---- + +#### Opérateurs booléens (avancé) + +Si `a`{.python} et `b`{.python} ne sont pas des booléens, la règle plus générale pour l'évaluation +des expressions utilisant des opérateurs booléens est la suivante : + +- `a and b`{.python} : Vaut `a` si `a` est équivalent à la valeur fausse, sinon vaut b. +- `a or b`{.python} : Vaut `a` si `a` est équivalent à la valeur vraie, sinon vaut `b`. + +---- + +### Opérateurs booléens (avancé, exemples) + +Toutes les instructions suivantes affichent `True`{.python} : + +```python {.numberLines} +print(("hello" and 0) == 0) +print((0 and "hello") == 0) +print(("hello" and 2) == 2) +print(("hello" or False) == "hello") +print((False or "") == "") +print("hello" is not False) +``` + +Ici, on teste en premier que `"hello" and 0`{.python} vaut bien `0`{.python}, et ainsi de suite… + +---- + +### Exemple avec quelques opérateurs + +```python {.numberLines} +distance = 17543 # 17543 mètres +kilometers = distance // 1000 # division entière par lots de 1000 mètres +remaining_meters = distance % 1000 # reste après la division entière +print(kilometers, "kilomètres et", remaining_meters, "mètres") + +print(2 ** 3) # affiche `8` +print(2 <= 3) # affiche `True` +``` + +Petit exemple de code avec conversion d'ordres de grandeur proportionnels (ex. mètres), +et usage d'autres opérateurs pour des opérations plus classiques. + +---- + +`a += b`{.python} est équivalent à → `a = a + b`{.python} + +Des opérateurs similaires sont disponibles pour les autres opérations arithmétiques : + +`-=`{.python}, `*=`{.python}, `/=`{.python}, `**=`{.python}, `//=`{.python} + et `%=`{.python} + +(_dans la pratique, on n'utilisera que très rarement autre chose que les opérations de base, mais le principe est là_) + +---- + +### Priorité des opérateurs en Python + +| Opérateurs | Signification | +|------------------------------------------------------------------|---------------------------------------------------| +| `()` | Parenthèses | +| `**` | Exposant | +| `+x`, `-x`, `~x` | Plus unaire, Moins unaire, NOT binaire | +| `*`, `/`, `//`, `%` | Multiplication, Division, Division entière, Modulo | +| `+`, `-` | Addition, Soustraction | +| `<<`, `>>` | Opérateurs de décalage binaire | +| `&` | AND binaire | +| `^` | XOR binaire | +| `\|` | OR binaire | +| `==`, `!=`, `>`, `>=`, `<`, `<=`, `is`, `is not`, `in`, `not in` | Comparaisons, Identité, Opérateurs d'appartenance | +| `not` | NOT logique | +| `and` | AND logique | +| `or` | OR logique | +| `:=` | Expression d'assignation | + +---- + +# Structures de contrôle + +---- + +## Conditions + +Dans tous les langages impératifs, on peut choisir de n'exécuter un bout de code que lorsque +certaines conditions sont vérifiées. En Python comme ailleurs, on utilise le mot-clé `if`{.python} +pour faire ce choix. + +Le mot-clé `if`{.python} est suivi d'une expression booléenne (`True`{.python} ou `False`{.python} +ou équivalent) qui permet de savoir si on exécute du code ou pas. + +```python {.numberLines} +a = 15 +if a > 10: # l'expression de comparaison renvoie un booléen True + print("A est bien supérieur à 10.") + print("Le bloc de la condition a bien été exécuté.") +print("Exécuté quoi qu'il arrive") +``` + +. . . + +Ce qui est exécuté pour cette condition est indenté de 4 espaces (on parle de bloc). Grâce à +l'indentation, Python sait où le code en question commence et où il s'arrête. + +---- + +## Syntaxe : blocs vides + +En Python, un bloc ne peut pas être vide (erreur de syntaxe), même si vous ne souhaitez rien y faire. +Si vous souhaitez écrire un bloc syntax(ct)iquement valide sans rien y faire, Python propose un mot-clé +spécifique à cet effet : `pass`{.python}. (Un commentaire ne suffit pas à former un bloc +valide car il est ignoré dans la grammaire Python) + +```python {.numberLines} +if True: + pass # utiliser une ellipse (...) fonctionne aussi mais peu utilisé +``` + +---- + +## Conditions : `if…else` + +Variante `if`…`else` : + +On peut exécuter du code si une condition est vraie, mais on peut aussi exécuter du code si cette +condition ne s'est pas produite ! Le mot-clé `else`{.python} est au même niveau d'indentation que +le `if`{.python}, et apparaît **une seule fois au maximum** pour le `if`{.python} auquel il est associé. + +```python {.numberLines} +a = 50 +if a > 75: + print("A est supérieur à 75") +else: + print("A est inférieur ou égal à 75") +``` + +---- + +## Conditions : `if…elif…else` + +On peut exécuter du code si une condition est vraie (`if`). Si elle est fausse, on peut exécuter du +code si une autre condition est vraie (`elif`), et ainsi de suite. La première condition vraie voit son bloc +exécuté, et l'interpréteur quitte ensuite la structure `if`{.python}. +Si un bloc `else`{.python} existe, il est toujours en dernier, et sera exécuté si toutes les conditions +le précédant ont été fausses. + +```python {.numberLines} +vote = 3 # Valeurs entre 1, 2 et 3 + +if vote == 1: + print("Vous avez voté pour Andre") +elif vote == 2: # Le vote n'est pas 1, mais 2 + print("Vous avez voté pour Beverly") +elif vote == 3: # Le vote n'est ni 1 ni 2, mais 3 + print("Vous avez voté pour Carlos") +else: # Aucun des cas de figure du dessus + print("Vote incorrect") +``` + +---- + +## Faire des boucles : `for … in liste` + +En programmation, une boucle consiste à répéter un bloc de code. En Python, le bloc est répété à +chaque fois qu'on parcourt un élément dans une liste. Par exemple, si on veut afficher les 10 +premiers nombres, de 0 à 9, on utilise le mot-clé `for`{.python} avec la fonction `range`{.python} : + +```python {.numberLines} +nombres = range(10) # une liste de 10 entiers de 0 à 9 inclus +for i in nombres: # Le bloc sera exécuté 10 fois + # La variable nommée i que nous avons déclarée sera modifiée par Python à chaque itération + print(i) # `i` contient tour à tour les nombres de 0 à 9 +``` + +**À noter** : la variable `i` reste disponible après l'exécution de la boucle et contient la dernière +valeur assignée lors de la boucle. + +---- + +### La fonction `range()`{.python} + +La fonction `range()`{.python} fournie par Python permet de générer des suites arithmétiques de nombres +entiers. Elle fonctionne avec un, deux ou trois arguments selon l'objectif. + +```python {.numberLines} +zero_to_nine = range(10) # stop (non inclus) +one_to_eight = range(1, 9) # start, stop +every_other_one = range(0, 10, 2) # start, stop, step +no_number_generated = range(10, 0, 2) # start, stop, step +``` + +---- + +## Faire des boucles : `while condition` + +Python propose un autre type de boucle `while`{.python} dont le bloc est exécuté tant qu'une +condition est vraie (une expression convertie en booléen). Dès qu'elle devient fausse au début d'une +itération, Python quitte la boucle et passe à la suite. + +```python {.numberLines} +nombre = 12 +while nombre > 10: + print(nombre) + nombre = nombre - 1 +``` + +**Attention** : Une boucle peut ne jamais se lancer, ou tourner indéfiniment ! +Dans un terminal normal, (au clavier) `⌨️ Ctrl + C` interrompt le script. Dans un lancement de script avec PyCharm, +seul le bouton `⏹ Stop` peut l'interrompre. + +---- + +## Exemple d'algorithme : Suite de Fibonacci + +**Suite de Fibonacci** : Une suite commençant par les nombres 0 et 1. On peut générer itérativement les +éléments successifs de la suite simplement; chaque nouveau nombre de la suite est la somme des deux qui le précèdent. + +Cela donne dans l'ordre : + +`0 1 1 2 3 5 8 13 21 34 55 89 144 …` + +Pour le résoudre, au choix, on utilise : + +- Deux variables (avec ou sans _unpacking_), ou trois avec une variable temporaire. +- Une boucle `while`{.python} (pour définir quand on s'arrête d'afficher un nouvel élément) + +---- + +### Fibonacci : unpacking + +En Python, le "dépaquetage" (**unpacking**) est une forme d'assignation de variables où, lorsque +l'expression à droite du signe `=` est une séquence à `n` éléments (avec `n > 1`), +vous pouvez assigner la séquence à `n` variables : + +```python {.numberLines} +a, b, c = (1, 2, 3) # a = 1, b = 2 et c = 3 +a, b = (1, 2, 3) # erreur, trop d'éléments à dépaqueter +a = (1, 2, 3) # aucun problème, a est une séquence de 3 éléments +``` + +. . . + +**Rappel** : si vous assignez la séquence à `1` variable, ça fonctionnera à nouveau, et votre +variable sera une séquence de `n` éléments. + +---- + +## Interrompre des boucles + +On peut interrompre une boucle `for`{.python} ou `while`{.python} avec deux mots-clés : + +- `break`{.python}, +- `continue`{.python}. + +---- + +### Interruption : `break`{.python} + +Lorsque l'on se trouve dans le bloc d'une boucle (seule la boucle directement englobante est concernée), +l'exécution d'une instruction `break`{.python} interrompt immédiatement la boucle en cours, qu'il s'agisse + d'un `for`{.python} ou d'un `while`{.python}. + +L'utilisation classique du mot-clé `break` s'applique aux traitements où vous exécutez une boucle (potentiellement +avec un nombre d'itérations que vous ne contrôlez pas) à la recherche d'une information. Dans ce cas précis, si +vous trouvez l'information qui vous intéresse avant la fin naturelle de la boucle, il n'est alors plus nécessaire +de la laisser se poursuivre; typiquement, si vous trouvez votre information à la ligne 10 d'un fichier de 900 000 +lignes, _pourquoi parcourir les 899 990 lignes restantes_ ? + +---- + +### `break`{.python} : Exemple + +Que fait cet exemple-ci ? + +```python {.numberLines} +for number in range(10 ** 9): + if number == 23: + print("Valeur trouvée") + break + else: + print("Itération...") +``` + +---- + +### Interruption : `continue`{.python} + +Lorsque l'on se trouve dans le bloc d'une boucle, l'exécution d'une instruction `continue`{.python} revient +immédiatement à la première ligne de l'itération suivante, ou autrement dit, ignore le reste du code de l'itération en cours. + +L'utilisation d'un mot-clé `continue`{.python} peut **toujours** être remplacée par un `if`{.python}, plus lisible. +Cependant, ce mot-clé peut servir à réduire le niveau d'indentation d'un bloc complexe : + +---- + +#### `continue`{.python} : Exemple + +```python {.numberLines} +for x, y in zip(a, b): + if x > y: + z = process_z(x, y) + if y - z < x: + y = min(y, z) + other_actions() +``` + +. . . + +Deviendrait comme suit. + +```python +for x, y in zip(a, b): + if x <= y: + continue + z = process_z(x, y) + if y - z >= x: + continue + y = min(y, z) + other_actions() +``` + +Très peu de développeurs s'en servent car le gain est minime à part pour ces raisons d'indentation. +Les cas d'indentation extrême doivent pouvoir être simplifiés d'une autre manière. + +---- + +## Bonus : Opérateur morse (walrus) + +Sans rentrer dans le détail, on peut, depuis Python 3.8 (fin 2019), simplifier des boucles `while`{.python} avec un opérateur `:=`{.python}. +C'est un opérateur qui permet d'assigner une valeur à une variable, mais contrairement au mot-clé `=`{.python}, l'opérateur +forme une expression dont la valeur est l'opérande de droite. On peut ainsi écrire : + +```python {.numberLines} +while (saisie := input("Saisissez oui :")) != "oui": + print("Saisie incorrecte") +``` + +. . . + +au lieu d'écrire : + +```python {.numberLines} +saisie = input("Saisissez oui :") # afficher l'invite et récupérer la saisie +while saisie != "oui": + print("Saisie incorrecte !") + saisie = input("Saisissez oui :") +``` + +---- + +## Opérateur morse : considérations + +Attention toutefois, l'opérateur possède la priorité la plus basse de tous les opérateurs Python, et dans +certains cas, l'expression l'utilisant **doit** employer des parenthèses pour ne pas provoquer d'erreur de +syntaxe. **Dans le doute, utilisez toujours des parenthèses.** + +```python {.numberLines} +a := 1 # Erreur de syntaxe +``` + +. . . + +```python {.numberLines} +(a := 1) # Ça fonctionne, mais ça n'a aucun intérêt +``` + +. . . + +```python {.numberLines} +print(a := 1 < 9) # Affiche True, et a == True +``` +. . . + +```python {.numberLines} +print((a := 1) < 9) # Affiche True, et a == 1, ce qu'on voulait +``` + +---- + +### Petit plus : expression ternaire + +En Python, il est possible de décrire une expression qui vaut une valeur `a` si une condition est +vraie, et `b` sinon. Sans cet opérateur, on écrit : + +```python {.numberLines} +if condition: + variable = a +else: + variable = b +``` + +. . . + +Avec cet opérateur, on écrira plutôt : + +```python {.numberLines} +variable = a if condition else b +``` diff --git a/documentation/03-exceptions.md b/documentation/03-exceptions.md new file mode 100644 index 0000000..b9d7472 --- /dev/null +++ b/documentation/03-exceptions.md @@ -0,0 +1,144 @@ +--- +title: Le droit aux erreurs +author: Steve Kossouho +--- + +# Le droit aux erreurs + +---- + +## Exceptions + +En Python, une exception est une erreur qui se produit pendant l'exécution de votre code. En tant que développeur, vous pouvez choisir ce que vous souhaitez faire quand une exception se produit, plutôt que de laisser le programme s'arrêter avec un message d'erreur. Les exceptions s'opposent entre autres aux erreurs de syntaxe, où l'interpréteur n'est pas même en mesure d'exécuter votre code. + +---- + +### Jargon des exceptions + +- `Lever une exception` : Ce que Python effectue lorsqu'on rencontre une erreur à l'exécution d'un script. Les exceptions générées par Python sont d'un type qui dépend de l'erreur rencontrée. Elles font toutes partie d'une hiérarchie dont le type le plus générique est nommé `Exception`. (voir programmation orientée objet et hiérarchie des classes d'exception) +- `Traceback` : Texte qui apparaît dans la sortie d'erreur (en rouge) lorsque votre programme plante à l'exécution. C'est un récapitulatif des exécutions d'instructions qui ont mené directement à l'interruption de l'exécution, accompagné d'informations sur l'exception. + +---- + +### Exemple d'exception + +Dans l'exemple ci-dessous, on effectue une division par zéro, mais on pourrait accéder à un mauvais indice de liste, une mauvaise clé de dictionnaire, un fichier verrouillé… + +```{.python .numberLines} +try: + 15 / 0 # erreur évidente pour l'exemple +except ZeroDivisionError: + pass +``` + +Gestion des erreurs de division par zéro + +---- + +![Hiérarchie des classes d'exception](assets/images/exception-class-hierarchy.png) + +---- + +### À ne pas faire + +Il est déconseillé d'utiliser directement la classe `Exception` (ou rien, d'ailleurs) avec la clause `except`; +ceci a pour effet de pousser votre code à réagir exactement de la même manière pour tous les cas de figure. +Si vous le tentez malgré tout, affichez ou conservez le traceback, vous me remercierez plus tard : + +```{.python .numberLines} +import traceback + +try: + print(15 / 0) +except Exception: # ou except: + traceback.print_exc() # Affiche le traceback dans la console +``` + +Voir [antipattern sur les exceptions pour plus d'info](https://realpython.com/the-most-diabolical-python-antipattern/) + +---- + +### Un bloc `except`, plusieurs exceptions + +On peut même avoir des blocs `except`{.python} prenant en charge plusieurs types d'exceptions, pour cela il suffit de les indiquer dans un tuple : + +```{.python .numberLines} +try: + pass # ou faire autre chose +except (TypeError, ValueError): + pass +``` + +---- + +### Un bloc `try`, plusieurs gestions + +On peut, à l'instar de la structure `if/elif/else`, faire suivre le bloc `try`{.python} de +plusieurs blocs `except`{.python} : + +```{.python .numberLines} +try: + print("Code à essayer") +except ValueError: + print("Code pour ValueError") +except TypeError: + print("Code pour TypeError") +``` + +---- + +Si aucun des blocs `except`{.python} ne gère précisément l'erreur qui se produit dans le bloc `try`{.python}, +alors l'interpréteur Python plante avec un traceback dans la console, comme attendu. + +```{.python .numberLines} +try: + 1 / 0 +except NameError: + pass +``` + +---- + +### Code exécuté si tout se passe bien + +La structure `try`{.python}...`except`{.python} peut être accompagnée d'un bloc `else`{.python}. Ce bloc +sera exécuté si aucun des blocs `except`{.python} précédents n'a été exécuté (comme dans une structure `if`{.python}) : + +```{.python .numberLines} +try: + value = input("Saisissez un nombre entier :") + value = int(value) +except ValueError: + value = None +else: + # Exécuté si le bloc try n'est pas interrompu par une erreur + print(f"Merci, la valeur est de {value}.") +``` + +---- + +### Exécution garantie + +Pour finir, il existe un bloc `finally`{.python}, dont le bloc est *toujours* exécuté, même si le programme doit planter : + +```{.python .numberLines} +try: + 15 / 0 +except KeyError: + pass +finally: + print("Toujours exécuté") +``` + +En général, on imagine l'utiliser lorsqu'on souhaite penser à toujours libérer une ressource (connexion, fichier etc.) + +---- + +On peut souhaiter également lever soi-même une exception pour notifier un problème à gérer. +C'est généralement le cas lorsque l'on fournit une API utilisable par d'autres développeurs. + +```{.python .numberLines} +def do_something(value): + if not isinstance(value, int): # si value n'est pas un entier + raise TypeError("Value must be an integer.") +``` diff --git a/documentation/04-functions.md b/documentation/04-functions.md new file mode 100644 index 0000000..cb16f32 --- /dev/null +++ b/documentation/04-functions.md @@ -0,0 +1,284 @@ +--- +title: Découvrir les fonctions +author: Steve Kossouho +--- + +# Découvrir les fonctions + +---- + +## L'utilité des fonctions + +Une fonction, c'est : + +1. Minimaliste si possible, +2. Réutilisable, +3. Un gain de temps et d'espace + +---- + +## Syntaxe de déclaration de fonctions + +```{.python .numberLines} +def my_first_function(): + # Affiche un texte à chaque fois qu'on l'exécute + print("Voici le code de la fonction") + +my_first_function() +``` + +---- + +## Typographie des fonctions + +Les noms de fonctions se choisissent, par convention, comme toute autre variable : + +- Tout en minuscules (ex. `exponential`) +- Mots séparés par des underscores (ex. `get_warning_count`) +- Peuvent contenir des chiffres sauf au début (ex. `log4`) + +---- + +## Référence _versus_ appel de fonction + +Lorsque vous définissez une fonction appelée `action` : + +`action` est une variable de type fonction dont vous pouvez ensuite exécuter le code associé. + +- `action` est donc la référence de la fonction. +- `action()`{.python} exécute le code de `action`, et récupère son expression de retour. + +---- + +## Valeurs de retour d'une fonction + +En mathématiques, une fonction renvoie toujours une valeur. +Par exemple, on peut déclarer `Pour tout x dans les nombres réels, f(x) = x × 15`. + +En Python, pour qu'une fonction qu'on déclare renvoie une valeur (transmette une valeur au code qui l'exécute) +lorsqu'on l'exécute, il faut utiliser le mot-clé `return`{.python}. + +Lorsque le mot-clé est rencontré par l'interpréteur, il interrompt immédiatement l'exécution de la +fonction et l'instruction qui a appelé la fonction récupère la valeur de l'expression qui a été retournée. + +```{.python .numberLines} +def multiply_by_five(value): # Fonction qui prend un argument nommé value + return value * 5 + +result = multiply_by_five(10) # l'expression `10 * 5` est assignée à la variable +print(result) # affiche 50 +``` + +---- + +### Valeurs de retour spécifiques + +Le mot-clé `return`{.python} a quelques comportements implicites : + +- Il peut être utilisé tout seul, sans expression : `return`{.python}. C'est équivalent à écrire `return None`{.python}, mais moins explicite. +- Si une fonction se termine sans avoir utilisé le mot-clé `return`{.python} : + - C'est toujours une fonction valide (on l'a vu dans le premier exemple) + - Implicitement, l'interpréteur Python retourne également la valeur `None`{.python}. + +. . . + +En clair, cela signifie qu'une fonction en Python renvoie **toujours** une valeur qui peut être assignée +à une variable, même si la valeur `None`{.python} a souvent peu d'utilité. + +---- + +## Passer quelques arguments aux fonctions + +Déclarer une fonction simple, c'est déjà pas mal, mais en déclarer une qui dépend de un ou +plusieurs arguments reçus en entrée, c'est bien plus utile ! + +Python propose au moins 4 types d'arguments différents, dont les usages sont évidemment différents, +et parmi ceux-ci, deux sont absolument essentiels et nous allons les aborder : + +1. Arguments positionnels +2. Arguments par défaut (avec valeur par défaut) + +---- + +## Arguments : Positionnels + +Derrière cet adjectif un peu pompeux se cache le type d'argument le plus simple à déclarer et à utiliser : + +```{.python .numberLines} +def f(x, y): + # Accepte deux arguments, affiche leur valeur + # Mais ne renvoie rien d'autre que `None` + print(x, y) + +f(1, 2) # exécute la fonction, donc affiche "1 2" +``` + +. . . + +Passer des valeurs à ces arguments est **obligatoire** lorsqu'on souhaite exécuter la fonction, +et les valeurs sont passées aux arguments dans le même ordre que dans la signature; +ici, à la ligne 5, `1`{.python} va dans `x`{.python} et `2`{.python} va dans `y`{.python}. +C'est de ce comportement que vient la notion de **positionnalité**. + +---- + +## Arguments : Valeurs par défaut + +```{.python .numberLines} +def f(x, alpha=15, beta=16): + # Accepte trois arguments, dont deux avec une valeur par défaut + print(x, alpha, beta) + return (x, alpha, beta) # renvoie un tuple + +f(1) # ça marche, alpha vaut 15, beta vaut 16 +f(46, 10, 12) # acceptable +f(99, alpha=23) # conseillé +f(99, 23) # équivalent à l'exemple du dessus +f(True, beta=23) # conseillé et obligatoire +f(True, , 23) # ceci est une erreur de syntaxe, on ne met pas deux virgules de suite en vrac +f(beta=23, x=50) # passer un arg. positionnel par son nom : déconseillé +``` + +. . . + +Les arguments avec valeur par défaut sont facultatifs; cela signifie que si le développeur les omet +lorsqu'il exécute la fonction, Python choisira pour ces arguments leur valeur par défaut. + +---- + +### Arguments : ordre + +Malheureusement, mais c'est techniquement nécessaire, il y a un ordre imposé par l'interpréteur Python +lorsque vous déclarez les arguments acceptés par une fonction : +les arguments positionnels **doivent** être déclarés **en premier** dans la liste des arguments, s'il y en a. + +. . . + +Tous les arguments, positionnels (obligatoires) et par défaut, peuvent cependant être passés par leur nom, +mais ne faites jamais ça, vous induirez vos relecteurs en erreur : + +```{.python .numberLines} +def f(x, alpha=15, beta=16): + return (x, alpha, beta) # renvoyer un tuple avec x, alpha et beta + +# x peut être passé par son nom, non positionnellement, mais c'est déconseillé +print(f(beta=23, x=50)) +``` + +---- + +## Bonus : Argument "étoile" (séquence) + +Il existe un type d'argument, qui n'apparaît qu'une seule fois **maximum**, et dont le nom est précédé d'une étoile dans la signature de la fonction. + +Cet argument apparaît après les arguments positionnels, et _de forte préférence_ avant les arguments avec valeur par défaut. +Lors de l'exécution de la fonction, cet argument contient toujours un tuple valide, même vide. +Également, comme cet argument contient toujours un tuple, il est généralement nommé avec un nom **au pluriel**. + +```{.python .numberLines} +def stretchable(number, *words): + print(number, words) # words est toujours un tuple + +stretchable(15, "word 1", "word 2", "word 3") # les 3 arguments vont dans le tuple `words` +stretchable(15, True, 3.14159) # les 2 arguments vont dans le tuple `words` +stretchable(1) # le tuple `words` sera vide +``` + +---- + +### Argument "étoile" : usage + +Un argument de ce type accepte, lors de l'appel de la fonction, un nombre de valeurs arbitraire (0 ou plus), et ces valeurs sont passées comme des arguments positionnels (sans nom d'argument). + +Cette technique est utilisée dans la fonction `print`{.python} pour pouvoir afficher à la suite plusieurs arguments. + +---- + +On peut directement renseigner une liste pour ce type d'argument, en passant, lors de l'appel de fonction, une expression de liste (ou tuple) précédée par une étoile : + +```{.python .numberLines} +def star_function(number, *words): + print(number, words) # words est toujours une liste + +star_function(15, *["word 1", "word 2", "word 3"]) # raccourci +``` + +TODO: Si arg étoile suivi de défaut, passer *[], suivi d'une valeur positionnelle, cette dernière s'ajoute quand même à l'argument étoile, et donc obligation passer l'argument par défaut via son nom. + +---- + +## Bonus : Argument "double-étoile" (dictionnaire) + +Un dernier type d'argument, apparaît aussi une seule fois **maximum**, et généralement en tout dernier dans les arguments. Celui-ci s'utilise en passant des noms d'arguments qui n'existent pas ailleurs dans la signature de la fonction : + +```{.python .numberLines} +def f_keywords(other=15, **kwargs): + print(kwargs) # toujours un dictionnaire + +f_keywords(plop="Hello", foo=19) # vont dans le dictionnaire `kwargs`. +``` + +On appelle aussi cet argument l'argument "mots-clés", et s'appelle très fréquemment `kwargs`. + +---- + +Si l'on appelle `f_keywords`{.python} avec un argument `plop`, Python regarde si un argument de ce nom existe. Si oui, la valeur de cet argument est modifiée. Si non, l'argument est ajouté comme association dans `kwargs`, de telle façon que `kwargs == {"plop": "Hello"}`{.python}. + +Souvent utilisé par coquetterie, mais l'argument pourrait être généralement remplacé par le simple passage d'un dictionnaire dans un argument positionnel. + +---- + +## Arguments : Ordre de déclaration + +Si vous deviez avoir dans vos fonctions tous les types d'arguments que nous avons vus, l'ordre de leur +apparition **devrait** être le suivant : + +1. `positionnel` (toujours premier) +2. `étoile` (utilisé positionnellement, toujours second) +3. `par défaut` (utilisé de préférence par nom, de préférence troisième) +4. `double-étoile` (utilisé par nom) + +---- + +## Superbonus : Arguments spéciaux + +---- + +### Arguments spéciaux : Slash + +Depuis Python 3.8 (2019), vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument +simplement nommé `/`{.python}. Il ne peut exister qu'une fois au maximum. + +Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le précèdent ne +peuvent pas être spécifiés autrement que positionnellement** : + +```{.python .numberLines} +def my_function(a, b, /, c, d): + print(a, b, c, d) + +my_function(1, 2, 3, 4) # autorisé +my_function(1, 2, c=3, d=4) # autorisé +my_function(1, b=2, c=3, d=4) # impossible, b est positionnel uniquement +``` + +Lorsqu'un argument `/`{.python} ou `*`{.python} est présent, les arguments `*args`{.python} sont interdits. La raison est que, si un tel +argument est présent, on est automatiquement tenu de passer les arguments qui suivent par leur nom. + +---- + +### Arguments spéciaux : Étoile + +Vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument +simplement nommé `*`{.python}. Il ne peut exister qu'une fois au maximum, et se trouver après l'argument +`/`{.python}. + +Lorsque vous spécifiez cet argument dans votre signature, **tous les arguments qui le suivent ne +peuvent être spécifiés autrement qu'en précisant leur nom** : + +```{.python .numberLines} +def my_function(a, b, c=3, *, d=4): + print(a, b, c, d) + +my_function(1, 2, 3, d=4) # autorisé +my_function(1, 2, 3, 4) # impossible, d ne peut pas être utilisé positionnellement +``` diff --git a/documentation/05-code-structures.md b/documentation/05-code-structures.md new file mode 100644 index 0000000..ffa04af --- /dev/null +++ b/documentation/05-code-structures.md @@ -0,0 +1,123 @@ +--- +title: Réutiliser du code +author: Steve Kossouho +--- + +# Réutiliser du code + +---- + +En Python, on peut écrire des choses simples avec un seul script. Mais +souvent, et même pour des choses simples, on peut se retrouver à écrire du code, organisé de façon un peu plus complexe, ou même du code qui réutilise des fonctionnalités en dehors de votre script. + +---- + +## Jargon : [Modules]{.naming} et [packages]{.naming} + +Jusque là, tout ce que nous avons écrit, c'est des [modules]{.naming}. Ce sont des fichiers .py (vides ou non, ils peuvent contenir du code). + +Il existe aussi les [packages]{.naming}. Ce sont des répertoires, pouvant contenir d'autres modules, et qui sont utilisables comme des modules (peuvent contenir du code). Pour pouvoir associer du code à ces répertoires et les considérer comme des packages, le langage Python impose que le code associé repose dans un fichier nommé `__init__.py` dans le répertoire. L'intérêt principal d'un package est d'y ranger d'autres packages et modules, pour organiser son code en arborescence cohérente. + +---- + +## Typographie des modules et packages + +Les modules et packages ont la même typographie que les variables (car Python les traite comme des variables de type `module`) : + +- Tout en minuscules (ex. `mypackage`) +- Sans espace ni tiret (ex. `my_package`) +- etc. + + +---- + +## Bibliothèque standard de Python + +Python est à la fois un langage et un exécutable interprétant des scripts écrits dans le langage. +L'interpréteur est toujours livré avec ce qu'on appelle la bibliothèque standard. +Il s'agit d'une immense bibliothèque de fonctionnalités, que l'on peut réutiliser dans nos programmes. + +La bibliothèque propose des outils pour manipuler du texte, du réseau, des bases de données, des fonctions mathématiques etc. + +[Liste des modules et packages de la bibliothèque standard](https://docs.python.org/3/library/) + +---- + +Parmi les très nombreux modules de la bibliothèque standard, assez peu vous serviront régulièrement. En voici une liste : + +- `random` : génération de nombres aléatoires +- `math` : fonctions mathématiques et trigonométriques +- `statistics` : fonctions statistiques, comme l'écart type. +- `pathlib` : outils pour gérer les chemins de fichier +- `datetime` : types pour gérer les dates + +D'autres peuvent servir ponctuellement, comme `csv` ou `sqlite3` pour nos exemples à venir. + +---- + +Comment accéder à ces nombreuses fonctionnalités ? +Par défaut, elles ne sont pas toutes accessibles dans votre code, excepté celles documentées dans les sections "built-in", et pour pouvoir les utiliser, il faut en faire la demande explicite dans vos modules via la notion d'`import` : + +Variantes : + +```{.python .numberLines} +# Les imports sont écrits au sommet d'un module +import math # vous avez maintenant une variable nommée `math` +from os import path # vous avez une variable `path` +import datetime as dt # datetime est utilisable en tant que dt uniquement + +from math import sin, cos # importer plusieurs fonctions de la même bibliothèque + +math.cos(math.pi / 2.0) # possible grâce à import math +cos(0) # possible grâce à from math import cos +path.join(…) +``` + +Chaque script qui utilise directement un _symbole_ doit toujours l'importer. + +**Note** : Pour importer le contenu d'un module, l'interpréteur Python doit toujours exécuter le contenu dudit module, afin d'en connaître le contenu. Attention donc à la présence de `print` dans ledit module. + +---- + +Note : Normalement, importer un package donne accès uniquement aux variables directement définies dans celui-ci, mais pas +aux sous-modules ou packages qui s'y trouvent. Si vous créez un package `package` contenant un sous-module `module1` : + +```{.python .numberLines} +import package + +print(package.module1) # ceci provoque une erreur +``` + +Cela ne fonctionne pas car Python ne charge pas directement les modules et packages présents à l'intérieur du package. +Pour y avoir accès, il faut que le package lui-même importe les éléments qui seront directement accessibles depuis celui-ci : + +```{.python .numberLines} +from . import module1 # ajoute une variable module1 dans le package +``` +`package/__init__.py` + +---- + +## Faire un petit peu de calcul avec la bibliothèque standard + +Avec l'outil que sont les imports, on peut avoir accès à de nombreuses fonctions de calcul. +Par exemple, on pourrait générer un nombre aléatoire et calculer un cosinus : + +```{.python .numberLines} +import random +import math + +random_number = random.randint(0, 100) # nombre entre 0 et 100 inclus +cosinus_result = math.cos(random_number) # cosinus du nombre aléatoire +``` + +---- + +## Bonus : Installer des paquets externes ([PyPI](https://pypi.org)) + +Avec PyCharm, on va installer simplement quelques paquets externes et utiliser leurs fonctionnalités : + +1. `requests` : Faire des requêtes HTTP plus simplement +2. `unidecode` : Translittération et désaccentuation +3. `attrs` : Accélérer l'écriture de classes + diff --git a/documentation/06-extra-types.md b/documentation/06-extra-types.md new file mode 100644 index 0000000..dcd8b72 --- /dev/null +++ b/documentation/06-extra-types.md @@ -0,0 +1,195 @@ +--- +title: Types supplémentaires +author: Steve Kossouho +--- + +# Types supplémentaires + +---- + +## Un type pour les dates et heures + +La bibliothèque standard nous offre plusieurs types de données pour gérer des moments dans le temps, avec le module `datetime`. Dans ce module, le type pour les dates avec heure s'appelle aussi `datetime`. + +```{.python .numberLines} +from datetime import datetime + +now = datetime.now() +then = datetime(2021, 1, 31) # arguments positionnels +then2 = datetime(2021, 1, 31, hour=12) # arguments par défaut +``` + +---- + +Les objets de ce type offrent un accès à plusieurs attributs, pour récupérer le jour, le mois, l'heure etc. + +```{.python .numberLines} +from datetime import datetime + +now = datetime.now() +print(now.day, now.date()) # affiche le jour du mois, et la date sans l'heure +``` + +---- + +## Opérations arithmétiques entre dates et intervalles de temps + +Le module `datetime` propose un type qui représente un intervalle de temps, nommé `timedelta`. +C'est ce que l'on obtient quand on soustrait deux dates (le temps écoulé entre les deux). +Mais on peut aussi créer des objets `timedelta`{.python} et les ajouter (ou soustraire) à des dates. + +```{.python .numberLines} +from datetime import timedelta, datetime + +interval = timedelta(hours=15) +now = datetime.now() +then = datetime(2000, 1, 1) +interval2 = now - then +the_future = now + interval # dans 15 heures +print(interval2, the_future) +``` + +---- + +Les objets d'intervalle de temps donnent accès à peu d'attributs. Nous avons uniquement accès aux jours, secondes et microsecondes. +On préférera utiliser le résultats renvoyés par la méthode `total_seconds()` comme base pour nos propres conversions d'ordres de grandeur. + +```{.python .numberLines} +from datetime import timedelta + +interval = timedelta(hours=14, minutes=31, seconds=53) +print(interval.days, interval.seconds, interval.microseconds) +print(interval.total_seconds()) +``` + +---- + +## Récupérer une date depuis un timestamp + +Un [timestamp]{.naming} est une date exprimée sous la forme d'un nombre entier (ou flottant). +En général, un timestamp en programmation est le nombre de secondes depuis le +1er janvier 1970 à 00:00:00 UTC. On appelle ce moment l'epoch Unix. + +On peut calculer un objet `datetime`{.python} depuis un timestamp, ou un timestamp depuis un objet `datetime`{.python}. + +```python {.numberLines} +from datetime import datetime + +timestamp = 1577836800 +as_datetime = datetime.fromtimestamp(timestamp) +print(as_datetime) +``` + +---- + + +## Convertir une date en chaîne + +Pour convertir une date vers une chaîne, ou convertir une chaîne vers un objet de date, consultez toujours la même ressource : + +[Table de référence pour le format de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes) + +---- + +### Éléments de date localisés dans la langue système + +Pour une raison inconnue, probablement un bug sous certaines distributions Linux, Python n'utilise pas la langue configurée sur votre système, +et vous voyez un formatage tel que `Sunday` s'afficher au lieu de `Dimanche`. +Pas de panique, il existe une solution pour forcer Python à utiliser la langue que vous désirez. + + +```{.python .numberLines} +import locale + +locale.setlocale(locale.LC_ALL, "") # utilise les paramètres de langue de l'utilisateur +``` + +[Documentation sur setlocale](https://docs.python.org/fr/3/library/locale.html) + +---- + +Pour convertir un objet `datetime` vers une chaîne, grâce à la table de référence, c'est simple : + +```{.python .numberLines} +from datetime import datetime + +now = datetime.now() +text = now.strftime("%d/%m/%Y %H:%M et %S secondes.") +other = f"{now:%d/%m/%Y %H:%M et %S secondes}" # via des f-strings +print(text, other) +``` + +---- + +## Convertir une chaîne en date + +Dans l'autre sens, c'est à peine plus compliqué : + +```{.python .numberLines} +from datetime import datetime + +text = "24 12 2003 15:17" +moment = datetime.strptime(text, "%d %m %Y %H:%M") +print(moment) +``` + +---- + +## Bonus : Fuseaux horaires + +Par défaut, les objets de date que vous confectionnez sont dits naïfs, car ils ne contiennent pas d'information de fuseau +horaire. Vous pouvez créer ou modifier des objets pour porter ces informations si vous en avez besoin. + +La façon de s'en servir changera selon que vous utilisez Python 3.9 ou une version antérieure. + +---- + +### Fuseaux horaires avant Python 3.9 + +Avant Python 3.9, il est conseillé d'installer `pytz` et `tzlocal` avec `pip`, puis de définir vos dates ainsi : + +```{.python .numberLines} +import pytz +from datetime import datetime + +moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("Europe/Paris")) +moment2 = datetime(2010, 1, 1) +moment2 = moment2.replace(tzinfo=pytz.UTC) +``` + +---- + +Vous pouvez convertir votre date de façon à la représenter dans un autre fuseau horaire : + +```{.python .numberLines} +import pytz, tzlocal +from datetime import datetime + +moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("America/Chihuahua")) +moment2 = moment.astimezone(tzlocal.get_localzone()) +``` + +---- + +### Fuseaux horaires avec Python 3.9+ + +Python 3.9 ajoute enfin `zoneinfo`, qui couvre presque totalement les larges lacunes de `tzinfo`. (il demeure impossible +de connaître le fuseau horaire local) + +```{.python .numberLines} +from datetime import datetime +from zoneinfo import ZoneInfo + +moment = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid")) +``` + +---- + +## Bonus : Bibliothèques tierces pour les dates + +L'écosystème Python propose de temps en temps des alternatives plus abordables que les +outils présents dans la bibliothèque standard. La gestion de dates n'y échappe pas et je peux proposer +deux bibliothèques élégantes et simples à comprendre pour Python : + +- [Arrow](https://arrow.readthedocs.io/en/latest/) : Better dates and times for Python +- [Pendulum](https://pendulum.eustace.io/) : Python datetimes made easy diff --git a/documentation/07-objects.md b/documentation/07-objects.md new file mode 100644 index 0000000..9cc043c --- /dev/null +++ b/documentation/07-objects.md @@ -0,0 +1,349 @@ +--- +title: Découvrir la programmation orientée objet +author: Steve Kossouho +--- + +# Découvrir la programmation orientée objet + +---- + +## La programmation objet ? Quoi, pourquoi ? + +La programmation orientée objet, c'est des outils de langage fournis par certains langages de programmation pour vous permettre de décrire et de manipuler des concepts (objets, types). +Lorsque l'on décrit un concept, on lui associe ce qu'on appelle des [attributs]{.naming} et [méthodes]{.naming} (comportements). + +Pour commencer, on peut imaginer un système où l'on mettrait en contact des propriétaires de chiens, +avec la possibilité de créer des fiches de leurs chiens : + +---- + +### Diagramme de classes UML + +![Diagramme UML représentant une classe de chiens](assets/images/classes-uml-dog.jpg) + +Exemple spartiate de diagramme de classes UML. + +---- + +## Découvrir la syntaxe de l'objet + +Dans les langages orientés objet, pour faire de l'objet, il faut écrire ou manipuler des **classes**. +Les **classes** sont des modèles utilisés pour créer des objets. +Dans l'exemple ci-dessous, Pierre et Marie sont des **objets** de la classe `Humain`. + +```{.python .numberLines} +class Human: + name = None + + def parler(self): + """Fonction uniquement disponible sur les humains""" + print(f"{self} parle.") + +pierre = Human() # nouvel objet de la classe Human +marie = Human() # encore un nouvel objet de la classe Human +pierre.parler() +``` + +---- + +## Typographie des classes + +La typographie des classes conventionnelle est un peu différente (enfin !) de celle des variables, fonctions, modules et packages. En Python, +pour nommer une classe, on utilisera le [PascalCase]{.naming} + +- Commence par une majuscule (ex. `Animal`) +- Ne contient jamais d'underscore; +- Les mots commencent par une majuscule (ex. `WildAnimal`) +- Les sigles et acronymes gardent toutes leurs majuscules (ex. `CRTMonitor`) + +---- + +## Les attributs + +Les attributs, ce sont simplement des variables, mais uniquement accessibles sur la classe ou ses objets. +Les attributs sont accessibles sur la classe et sur les objets de la classe. Tout objet instancié possède les mêmes valeurs d'attributs que la classe. + +```{.python .numberLines} +class Animal: + name = None + +animal1 = Animal() # Crée un nouvel animal et l'assigne à une variable +print(animal1.name) # Afficher la valeur de l'attribut `name` +``` + +[Exercice 1](https://github.com/sk-dwtoulouse/python-initiation-training/blob/main/exercices/07-objects/01-base-class.asciidoc#exercice-1) + +---- + +## Attributs : manipulation + +Préférez manipuler des attributs sur les objets plutôt que sur la classe. Le reste, c'est très simple, et on peut même ajouter de nouveaux attributs : + +```{.python .numberLines} +class Dummy: + attribute1 = 19 + +item = Dummy() +item.new_attr = "Hello" # nouvel attribut +item.attribute1 = 60 # modifier un attribut +``` + +[Exercice 2](https://github.com/sk-dwtoulouse/python-initiation-training/blob/main/exercices/07-objects/01-base-class.asciidoc#exercice-2) + +---- + +## Méthodes + +Les méthodes, c'est exactement la même chose que les fonctions (sauf l'argument `self` qui est implicite) : + +```{.python .numberLines} +class Dummy: + def dummy_func(self): + print(self) + +item = Dummy() +item.dummy_func() # ben, et self ?? +``` + +Seules les instances de la classe `Dummy`{.python} peuvent utiliser la méthode nommée `dummy_func()`{.python}; +vous avez la certitude de ne pas utiliser cette méthode sur les objets d'une classe incorrecte. + +---- + +## L'argument `self` + +Quand vous écrivez des classes et que vous ajoutez des fonctions (on appelle ça des **méthodes**), +elles ont toujours un premier argument nommé `self`. Il récupère toujours la référence de l'objet sur lequel vous avez demandé à exécuter la méthode. + +Quand vous appelez la méthode **sur un objet** (et pas sur une classe), ne passez pas de valeur +entre parenthèses pour l'argument `self` : +Python passe _implicitement_ l'objet sur lequel on a appelé la méthode à l'argument `self`. + +```{.python .numberLines} +class Dummy: + def foo(self, number): + print(number) + +dummy = Dummy() +# `dummy` est implicitement passé dans `self` +dummy.foo(15) # l'argument `number` reste obligatoire +``` + +[Exercice 3](https://github.com/sk-dwtoulouse/python-initiation-training/blob/main/exercices/07-objects/01-base-class.asciidoc#exercice-3-m%C3%A9thodes) + +---- + +## Différences entre une classe et ses objets + +- La classe sert de modèle pour instancier des objets +- Les nouveaux objets possèdent toutes les propriétés de la classe +- Les nouveaux objets vivent indépendamment les uns des autres +- Les objets sont des objets, la classe est une classe + +---- + +## Instancier en passant des arguments + +```{.python .numberLines} +class Car: + doors = 5 + gearbox = "manual" # transmission + brand = None # marque du véhicule +``` + +Avec cette déclaration de classe, créer un objet et l'initialiser prend quelques lignes… : + +```{.python .numberLines} +car = Car() +car.doors = 3 +car.gearbox = "automatic" +car.brand = "Seat" +``` + +---- + +C'est un peu long, notamment si l'on doit initialiser plusieurs objets qui ont beaucoup d'attributs. +Il peut être intéressant de pouvoir instancier un objet d'une classe en utilisant des arguments, +qui seraient utilisés pour modifier les attributs du nouvel objet, ex. : + +```{.python .numberLines} +car = Car(doors=3, gearbox="automatic", brand="Seat") # une ligne au lieu de 4 +``` + +---- + +Pour ce faire, il faut définir ou redéfinir dans notre classe ce qu'on appelle en Python une +**méthode spéciale** (ou "dunder") nommée spécifiquement `__init__`. Le nom de cette méthode est +défini dans le langage Python. + +Cette méthode, si elle existe dans notre classe, est exécutée lorsque l'on instancie un nouvel objet, +et les arguments passés entre parenthèses sont transmis à cette méthode : + +```{.python .numberLines} +class Car: + doors = 5 + gearbox = "manual" + brand = None + + def __init__(self, doors=5, gearbox="manual", brand=None): + # Grâce à cette méthode, on peut créer un objet en passant des arguments + # avec les noms "gearbox", "doors" et "brand", tous facultatifs (None par défaut) + self.doors = doors # self est l'objet que l'on vient de créer, doors est un argument + self.gearbox = gearbox + self.brand = brand + +lamborghini1 = Car(doors=3, brand="Lamborghini") +``` + +[Exercice 4](https://github.com/sk-dwtoulouse/python-initiation-training/blob/main/exercices/07-objects/01-base-class.asciidoc#exercice-4-red%C3%A9finition-de-linstanciation) + +---- + +## Héritage  et Polymorphisme  + +---- + +### Héritage + +L'héritage est un concept simple à appréhender : + +```{.python .numberLines} +class Animal: + life_expectancy = None + +class Vertebrate(Animal): # Classe parente mise entre parenthèses + vertebrae_count = None + +dog = Vertebrate() +# Informations sur l'objet et les classes +print(issubclass(Vertebrate, Animal)) # Vertebrate est-elle une spécialisation de Animal ? +print(isinstance(dog, Vertebrate)) # dog est-il un vertébré ? +print(isinstance(dog, Animal)) # dog est-il un animal ? +``` + +L'**héritage** permet de partir d'une classe de base, et de créer une autre classe plus spécialisée. Ici, +les vertébrés sont effectivement une sous-classe du règne animal. Ils ont les mêmes attributs que tous +les animaux (et les mêmes méthodes), mais ont peut-être des attributs et méthodes propres aux vertébrés. + +---- + +### Polymorphisme + +Le polymorphisme en Python, c'est le fait de pouvoir redéfinir une méthode dans une classe enfant : + +```{.python .numberLines} +class Animal: + life_expectancy = None + + def move(self): + print(f"Do something general with {self}") + +class Vertebrate(Animal): + vertebrae_count = None + + def move(self): # On redéfinit move + super().move() # appelle `move` comme défini dans la classe parente + print("Do something different with vertebrae.") +``` + +**Note** : Une méthode redéfinie peut posséder une signature différente de celle existant +dans la classe parente. + +---- + +### Le polymorphisme et la fonction `super()` + +Lorsque vous créez une classe enfant, qui redéfinit une méthode de la classe parente (ex. vous redéfinissez `move()`), +il va souvent vous arriver de souhaiter recopier le code de la méthode que vous aviez dans la classe parente, et y +ajouter quelques lignes. + +Plutôt que d'en recopier le code, Python vous propose la fonction `super()`, utilisable uniquement +dans une méthode d'une classe qui utilise l'héritage. Cette fonction vous renvoie automatiquement +votre objet `self`, mais il est modifié de façon à ce que tout appel de méthode sur cet objet +exécute le code de la méthode tel que défini dans la classe parente. + +---- + +## Bonus : Courte introduction aux décorateurs avec @staticmethod + +Des fois, dans une classe, on souhaite placer des méthodes, qui sont utiles vis-à-vis de la classe, +mais qui ne sont pas directement liées à des objets de la classe. Pour simplifier, on aimerait aussi se +passer de l'argument `self`, et s'en servir comme de simples fonctions. + +C'est possible, grâce au décorateur `@staticmethod`. + +---- + +```{.python .numberLines} +class Car: + power_horse = None + wheel_count = None + + @staticmethod + def create_car_from_file(path): + """Function to create car from file.""" + return Car() +``` + +La fonction est rangée dans la classe comme si cette dernière était un package ou un module. +Il ne faut pas en abuser mais c'est très pratique. + +---- + +## Bonus : Introspection + +L'introspection, c'est le fait, dans votre script, d'aller chercher des informations sur vos variables +alors même que le programme est en train de tourner. C'est utilisé pour vérifier les types des variables, +récupérer les noms des attributs d'un objet, etc. + +---- + +### Quelques fonctions d'introspection + +```{.python .numberLines} +class Car: + wheel_count = 4 + +car1 = Car() +print(getattr(car1, "wheel_count", None)) # renvoie car1.wheel_count, ou None si introuvable +print(setattr(car1, "gearbox", None)) # exécute car1.gearbox = None +print(hasattr(car1, "wheel_count")) # Renvoie si l'attribut existe dans l'objet +print(dir(car1)) # liste les noms d'attributs de l'objet +print(isinstance(car1, Car)) # car1 est-elle une voiture ? +print(type(car1)) # renvoie la référence de la classe de l'objet +``` + +---- + +## Superbonus : Encapsulation + +Dans d'autres langages objet (pas en Python), l'encapsulation consiste, dans le corps d'une classe, +à indiquer si des attributs de cette classe sont accessibles depuis le reste du code. Cela permet aux +développeurs utilisant nos classes d'avoir la certitude qu'on ne touche pas directement à l'attribut. + +En Python, le concept d'encapsulation n'existe pas, **mais** on peut s'en approcher d'une certaine façon... + +---- + +Nommer un attribut en le faisant précéder d'un double underscore (`__`) provoque un comportement spécifique +de l'interpréteur Python : l'attribut est accessible avec son nom dans les méthodes de la classe, +alors qu'il n'est accessible qu'avec un autre nom en dehors de la classe. +Voir l'[article de Dan Bader sur la signification des underscores](https://dbader.org/blog/meaning-of-underscores-in-python). + +---- + +```{.python .numberLines} +from uuid import UUID, uuid4 + +class Person: + __uuid: UUID = None + + def __init__(self): + self.__uuid = uuid4() + +# Tester le "name mangling d'attributs" +if __name__ == "__main__": + person = Person() + print(getattr(person, "__uuid", "not found")) + print(getattr(person, "_Person__uuid", "not found")) +``` diff --git a/documentation/08-files-paths.md b/documentation/08-files-paths.md new file mode 100644 index 0000000..0b53300 --- /dev/null +++ b/documentation/08-files-paths.md @@ -0,0 +1,77 @@ +--- +title: Informations des répertoires et fichiers +author: Steve Kossouho +--- + +# Exploiter le système de fichiers + +---- + +## Le package `pathlib` + +Le module `pathlib` de Python 3.4+ (2014) offre des classes orientées objet pour manipuler les chemins de fichiers. Il s'agit +d'une interface moderne orientée objet pour compléter ou remplacer ce qui se faisait avec le module `os.path`. + +---- + +### Les objets `pathlib.Path` + +L'objet `Path` du module `pathlib` représente un chemin de fichier général et offre des méthodes et des propriétés +pour effectuer diverses opérations sur ledit chemin. + +```python {.numberLines} +from pathlib import Path + +# Créer un objet Path +p = Path('/chemin/vers/fichier') +``` + +Créer un chemin. _Le chemin peut ou non exister réellement sur le système local, la seule contrainte étant qu'il soit +valide par rapport à la norme POSIX (et Windows)_. + +---- + +### Méthodes utiles des objets `pathlib.Path` + +Les objets `Path` ont plusieurs méthodes utiles pour gérer un chemin de fichier ou de répertoire. Parmi les outils +qui renvoient les informations les plus simples : + +```python {.numberLines} +from pathlib import Path + +# Imaginons que bob est un répertoire +f = Path("/home/bob") +# Vérifier si un chemin existe +print(f"Le chemin existe : {f.exists()}") + +# Générer un objet Path qui est un répertoire enfant de bob +f2 = f / "morane" +# M'affiche "/home/bob/morane" +print(f2) + +# Vérifier si un chemin est un répertoire +if p.is_dir(): + print("C'est un répertoire.") + +# Vérifier si un chemin est un fichier +if p.is_file(): + print("C'est un fichier.") +``` + +---- + +### Parcourir récursivement des fichiers avec `pathlib.Path` + +La méthode `rglob()` des objets `Path` peut être utilisée pour parcourir récursivement des fichiers. + +```python {.numberLines} +from pathlib import Path + +# Parcourir récursivement tous les fichiers .txt +for fichier in Path('/chemin/vers/répertoire').rglob('*.txt'): + print(fichier) + +# Parcourir tous les fichiers .txt du répertoire, sans récursion +for fichier in Path('/chemin/vers/répertoire').glob('*.txt'): + print(fichier) +``` diff --git a/documentation/08-text-files-xml.md b/documentation/08-text-files-xml.md new file mode 100644 index 0000000..39a40ef --- /dev/null +++ b/documentation/08-text-files-xml.md @@ -0,0 +1,124 @@ +--- +title: Manipuler des fichiers texte XML +author: Steve Kossouho +--- + +# Découvrir comment décoder des arborescences XML + +---- + +## Structure d'un fichier XML + +Le format XML (_Extensible Markup Language_) est un format de texte permettant de représenter des données +hiérarchiques (avec un élément principal) arbitraires. Le contenu d'un document de ce type utilise une syntaxe +à base de balises telles qu'on les retrouve en SGML ou HTML : + +```xml + + + Empire Burlesque + Bob Dylan + USA + Columbia + 10.90 + 1985 + + +``` + +Extrait de document d'exemple. [Lien du document](https://www.w3schools.com/xml/cd_catalog.xml) + +---- + +## Définition de la structure d'un document XML + +Professionnellement, il peut être intéressant pour un producteur, ou un consommateur de fichiers +XML d'avoir accès à un document normalisant le contenu possible d'un fichier XML. + +Pendant un temps, seules les [DTD](https://fr.wikipedia.org/wiki/Document_type_definition) existaient +mais étaient écrites dans un format assez indigeste. En 2001, le [XML Schema](https://fr.wikipedia.org/wiki/XML_Schema) +est plus accessible, et certains outils Python sont capables d'utiliser ces documents pour valider une +structure XML. + +---- + +## Utilisation du XML en Python + +Si l'on connaît la structure d'un document XML, il est possible de le lire facilement en Python. +Même si les packages de la bibliothèque standard fonctionnent, ils sont **spécifiquement** +indiqués comme sensibles à des attaques de document malicieusement formé (typiquement XML Bomb, attaque sur le +système de références en XML). + +Parmi les autres bibliothèques, la plus utilisée dans l'écosystème Python semble être [LXML](https://lxml.de) + +```{.bash .numberLines} +pip install lxml # pour installer la bibliothèque externe +``` + +---- + +### Exemple de démo de LXML + +Pour naviguer dans un document XML, il existe plusieurs façons de faire : + +- Méthode récursive, où l'on récupère un élément pour parcourir ses enfants +- Méthode XPATH, où l'on référence des éléments par rapport à leur "chemin" dans le document + +La plus simple des méthodes disponibles consiste à se baser sur le XPATH pour trouver des éléments : + +```{.python .numberLines} +from lxml import etree + +tree = etree.parse(r"source.xml") # récupère l'élément racine +# Récupérer les éléments de la racine CATALOG qui ont le nom CD +items = tree.xpath("/CATALOG/CD") +``` + +- [Guide complet sur le XPath](https://www.ionos.com/digitalguide/websites/web-development/xpath-tutorial/) +- [Exemple plus simple sur le XPath](https://www.w3schools.com/xml/xpath_syntax.asp) + + +---- + +### Parcourir des résultats XPATH + +Dans l'exemple précédent, nous avons pu récupérer, via une "requête" XPATH, un possible ensemble d'éléments. +Ces éléments peuvent être parcourus avec une simple boucle `for`{.python} : + +```{.python .numberLines} +from lxml import etree + +tree = etree.parse(r"source.xml") # récupère l'élément racine +# Récupérer les éléments de la racine CATALOG qui ont le nom CD +items = tree.xpath("/CATALOG/CD") + +for cd in items: + for attribute in cd: + # afficher le nom et les attributs, puis le texte + print(attribute.tag, attribute.attrib, attribute.text) +``` + +---- + +## Propriétés des éléments `_ElementTree` + +Les éléments du modèle de document sont représentés sous la forme d'instances de la classe +`_ElementTree`. Pour en extraire des données, de nombreuses méthodes sont documentées officiellement, +mais les attributs les plus simples à retenir sont les suivants : + +- `attrib` (`dict`{.python}) : renvoie les attributs de la balise; +- `tag` (`str`{.python}) : renvoie le nom de la balise; +- `text` (`str`{.python}) : renvoie le texte direct de la balise. + +Également, un élément peut être parcouru avec une boucle `for`{.python} et renverra à +chaque itération chacun de ses éléments enfants, même si la méthode suivante existe aussi : + +- `getchildren()`{.python} : renvoie un itérable des éléments enfants. + +---- + +## Documentation officielle de LXML + +- [Documentation officielle (en anglais)](https://lxml.de) +- [Tutorial LXML par Oxylabs](https://oxylabs.io/blog/lxml-tutorial) +- [Sérialiser des objets Python en XML](https://pypi.org/project/lxml-dataclass/) diff --git a/documentation/08-text-files.md b/documentation/08-text-files.md new file mode 100644 index 0000000..8518c57 --- /dev/null +++ b/documentation/08-text-files.md @@ -0,0 +1,410 @@ +--- +title: Manipuler des fichiers texte +author: Steve Kossouho +--- + +# Découvrir comment manipuler des fichiers texte + +---- + +## Écrire et lire des fichiers (version de base) + +Python vous offre, sans import nécessaire, une fonction `open`{.python} vous permettant d'ouvrir des +fichiers pour les manipuler. Cette fonction semble provenir du module `io`{.python} de la +bibliothèque standard. + +Pour ouvrir un fichier en écriture : + +```python {.numberLines} +file = open("fichier.txt", "w", encoding="utf-8") # Ouvrir le fichier +file.write("Texte à écrire\nDeuxième ligne.\n") +file.write("Troisième ligne.") +file.close() # Toujours penser à le refermer, pour votre système +``` + +---- + +La fonction `open()`{.python} prend quelques arguments importants : + +- `filename` : chemin de fichier relatif (au répertoire de travail) ou absolu +- `mode` : `"w"` pour write, `"r"` pour read, `"a"` pour append +- `encoding`: rendez-le explicite, et "utf-8" si possible + +---- + +### Pages de code les plus fréquemment rencontrées : + +1. `utf-8` : ±90% du temps (complètement rétrocompatible avec `ASCII`) +2. `windows-1252` ou `1252` : ±5% du temps (provient de Windows 95) +3. `latin-1` : ±5% du temps (aussi nommé `iso8859-1`) +4. `utf-16` : certains pays n'utilisant quasiment pas de caractères ASCII, ils produisent souvent de l'UTF-16 (ex. Chine, Russie) + +---- + +### Plus : Échappement de caractères + +- Échappements classiques 0 à 8 bits (_0 à 255_) +- Échappements de caractères 0 à 16 bits (_256 à 65535_) +- Échappements de caractères 0 à 32 bits (_65536 et plus_) + +```python {.numberLines} +print("\x41 = \101 = A") # codes 8 bits, 2 caractères obligatoires +print("\u00E6 = æ") # codes 16 bits, 4 caractères obligatoires +print("\U0001F44D = 👍️") # codes 32 bits, 8 caractères obligatoires +``` + +[Algorithme UTF-8](https://en.wikipedia.org/wiki/UTF-8) + +---- + +### Ouvrir un fichier en lecture + +```python {.numberLines} +file = open("fichier.txt", "r", encoding="utf-8") +line1 = file.readline() # Lit une ligne, et avance le curseur à la ligne suivante +rest1 = file.read() # Lit le fichier jusqu'à la fin +file.close() # Toujours penser à le refermer, pour votre système +``` + +---- + +### Outils disponibles pour gérer des fichiers + +Si l'on utilise des éditeurs de texte, on pourrait penser qu'il est facile de demander à Python de, par exemple : + +```{.text .numberLines} +- Remplacer une ligne +- Lire une ligne arbitraire d'un document +- Supprimer une ligne +- Remplacer du texte +``` + +Aucune de ces fonctionnalités n'existe en standard, dans aucun langage; les logiciels qui vous permettent +ces manipulations sont obligés, souvent, de conserver une copie du document en mémoire (quand c'est possible) +et d'effectuer les manipulations en mémoire avant de réécrire tout ou partie du fichier. + +Tout ce qu'on a d'utile, c'est : + +```{.text .numberLines} +- Ajouter du contenu à la fin +- Réécrire le fichier +- Lire ligne par ligne du début, jusqu'à arriver à une ligne arbitraire +- Déplacer le curseur à une position en octets +``` + +---- + +Une bibliothèque externe Python propose des outils pour effectuer certaines de ces actions : + +```bash {.numberLines} +pip install textfile +``` + +[Page PyPI du package textfile](https://pypi.org/project/textfile/) + +---- + +## Écrire et lire des fichiers (gestionnaire de contexte) + +Une version raccourcie du `f = open()`{.python} … `f.close()`{.python} consiste à utiliser un gestionnaire de +contexte (la formation Python intermédiaire explique le concept). La syntaxe consiste en ce qui suit : + +```python {.numberLines} +with open("fichier.txt", "r", encoding="utf-8") as file: + # `file.close()` : appelé automatiquement en fin de bloc + text = file.read() +``` + +À la fin de l'exécution du bloc, une méthode spéciale est automatiquement appelée et ferme le descripteur +de fichier s'il est resté ouvert. Plus besoin d'exécuter manuellement `file.close()`{.python} + +---- + +### Bonus : Ouverture simultanée de fichiers + +Avec un seul bloc `with` … `as`, il est possible d'utiliser plusieurs gestionnaires de contexte en même +temps, par exemple, si l'on veut ouvrir un fichier en lecture, faire une conversion de données et les +écrire dans un fichier ouvert en écriture, on peut : + +```python {.numberLines} +with open("input.txt", "r") as infile, open("output.txt", "w") as outfile: + data = infile.read().upper() # tout mettre en majuscules + outfile.write(data) +``` + +---- + +## Parcourir facilement les lignes d'un fichier + +Il est possible, lorsque vous avez un descripteur de fichier ouvert, de parcourir facilement ligne à ligne +le contenu de votre fichier texte, en utilisant le mot-clé `for`{.python} : + +```python {.numberLines} +with open("fichier.ext", "r", encoding="utf-8") as file: + for line in file: + print(line) +``` + +En interne, ici la fonction `open()`{.python} est exécutée en deux temps; un première fois pour renvoyer +le descripteur de fichier, et une seconde fois lors de la fin du bloc... Mais c'est un peu magique, et c'est +un sujet pour une formation plus avancée de Python. + +---- + +## Formats structurés : JSON + +Le **JSON** (JavaScript Object Notation) est un format de texte extrêmement populaire +pour partager des données hiérarchiques. Il a largement supplanté le XML dans les systèmes +modernes et les services web. Les données contenues dans un fichier texte au format JSON peuvent être +interprétées et transformées en données Python, telles que `dictionnaires` et `listes`, `nombres` etc. + +---- + +### Lecture et écriture de fichiers JSON + +Il est extrêmement facile de lire ou d'écrire du contenu depuis ou vers un fichier +représentant une structure JSON. [Documentation du module JSON](https://docs.python.org/fr/3/library/json.html) + +```python {.numberLines} +import json + +# Lire un fichier JSON +with open("fichier.json", "r", encoding="utf-8") as file: + data = json.load(file) + +# Écrire un fichier JSON, l'objet à écrire doit être une liste ou +# un dictionnaire +with open("copie.json", "w", encoding="utf-8") as file: + json.dump(data, file, indent=2) +``` + +---- + +## Formats structurés : CSV + +Le CSV est un format accessible et non propriétaire pour représenter des données tabulées (en table) +. C'est un format texte, utilisant, par défaut, des virgules et des retours à la ligne pour séparer +les lignes et colonnes. + +La manipulation des CSV fait aussi partie de la bibliothèque standard de Python. [Documentation CSV](https://docs.python.org/3/library/csv.html) + +---- + +### Parcourir les lignes d'un fichier CSV + +Lire le contenu d'un fichier CSV est presque aussi simple que pour un fichier JSON, à quelques détails près : + +```python {.numberLines} +import csv + +with open("fichier.csv", "r", encoding="utf-8") as file: + reader = csv.reader(file, delimiter=",") + for row in reader: + print(row) # Affiche une ligne sous forme d'une liste de chaînes de caractères +``` + +Vous ouvrez d'abord votre fichier en lecture et en mode texte, comme tout fichier texte, puis vous créez un objet de type +lecteur, configuré pour lire et interpréter le contenu de lignes du document. Par défaut, le lecteur ne reconnaît que les +documents dont les cellules sont séparées par la virgule `,` et dont les lignes sont séparées par `\n`. +Heureusement, cet objet peut être configuré pour comprendre des fichiers avec des propriétés différentes. + +---- + +### Paramètres de formatage d'un fichier CSV + +Pour lire ou écrire un fichier CSV, il est possible de configurer les objets en charge d'interpréter ou de formater le +contenu du fichier. En lecture, vous configurerez un objet de type `reader`, et en écriture... `writer`. Dans les deux cas, la procédure sera la même. + +Vous avez trois façons de configurer votre objet lecteur ou écrivain : + +- Soit en passant un objet de type `Dialect`, un objet dont les attributs servent à configurer toutes les facettes du formatage d'un fichier CSV; +- soit en passant un nom d'objet de type `Dialect`, par exemple `"excel"` (séparateur virgule); +- soit en passant des arguments individuels qui correspondent aux attributs des objets `Dialect`. + +---- + +#### Configuration via un objet Dialect + +Pour définir votre propre `Dialect`, vous pouvez créer une classe héritant de `Dialect`, dans laquelle vous n'avez qu'à +redéfinir les attributs dont vous souhaitez changer la valeur. Voir [Classe Dialect du module CSV](https://docs.python.org/fr/3/library/csv.html#dialects-and-formatting-parameters) +pour connaître les valeurs de base. + +```python {.numberLines} +import csv + +class MonDialecte(csv.Dialect): + """Dialecte CSV utilisant des // comme séparateur.""" + delimiter = "//" +``` + +---- + +Une fois que votre dialecte est défini et prêt à l'usage, vous pouvez l'utiliser pour lire ou écrire un fichier : + +```python {.numberLines} +import csv + +class MonDialecte(csv.Dialect): + """Dialecte CSV utilisant des // comme séparateur.""" + delimiter = "//" + +with open("fichier.csv", "r", encoding="utf-8") as file: + reader = csv.reader(file, dialect=MonDialecte()) + for row in reader: + print(row) +``` + +---- + +Plutôt que de créer une classe de dialecte pour personnaliser la manipulation d'un fichier, il est possible de passer à l'argument `dialect` +une chaîne de caractères représentant le nom d'un dialecte prédéfini. Par défaut, les valeurs disponibles sont `"excel"`, `"excel-tab"` et `"unix"`. + +```python {.numberLines} +... +reader = csv.reader(file, dialect="excel") +``` + +Vous pouvez aussi enregistrer des noms de dialecte supplémentaires en utilisant la fonction [`csv.register_dialect(name, dialect)`](https://docs.python.org/fr/3/library/csv.html#csv.register_dialect). + +```python {.numberLines} +import csv + +class MonDialecte(csv.Dialect): + """Dialecte CSV utilisant des // comme séparateur.""" + delimiter = "//" + +csv.register_dialect("mondialecte", MonDialecte) +``` + +---- + +#### Configuration via les attributs de Dialect + +Pour gagner du temps, il est possible, lorsque vous créez votre objet lecteur ou écrivain, de passer des arguments pour +préciser le format du fichier CSV à lire ou à écrire. Ces arguments ont les mêmes noms que les attributs de la classe `Dialect`, et ont le même usage. + +```python {.numberLines} +import csv + +with open("fichier.csv", "r", encoding="utf-8") as file: + reader = csv.reader(file, delimiter=";", doublequotechar=True) # etc., etc. + for row in reader: + print(row) +``` + +---- + +### Détecter le dialecte d'un fichier + +Outre la configuration de dialecte manuelle, il est possible de demander à Python d'autodétecter les propriétés de formatage d'un fichier CSV, +et de générer automatiquement un objet `Dialect`. Pour cela, vous devez utiliser la classe `csv.Sniffer` : + +```python {.numberLines} +import csv + +with open("output.csv", "r", encoding="utf-8") as file: + dialect = csv.Sniffer().sniff(file.read()) # Lire le contenu du fichier pour détecter le dialecte + file.seek(0) # Revenir au début du fichier pour démarrer la lecture + reader = csv.reader(file, dialect=dialect) + for row in reader: + print(row) +``` + +---- + +### Exemple : Copier un fichier CSV vers un fichier cible + +On peut avec le module CSV lire un contenu CSV dans un objet Python, puis réécrire le contenu +de cet objet dans un nouveau fichier CSV. + +```python {.numberLines} +import csv + +table = list() # Objet à utiliser pour stocker le contenu +with open("fichier.csv", "r", encoding="utf-8") as file: + reader = csv.reader(file, delimiter=",") + for row in reader: + table.append(row) # Ajouter la ligne comme élément de `table` + +with open("copie.csv", "w", encoding="utf-8") as file: + writer = csv.writer(file, delimiter=";") + writer.writerows(table) # table doit être une liste de listes +``` + +---- + +### Lire chaque ligne sous forme de dictionnaire + +Si votre fichier CSV contient des en-têtes, et que vous préférez les utiliser pour retrouver le +contenu d'une colonne, plutôt qu'utiliser son indice, vous pouvez procéder +à [l'utilisation d'un `DictReader`](https://docs.python.org/fr/3/library/csv.html#csv.DictReader) : + +```python {.numberLines} +import csv + +with open("example-file.csv", "r", encoding="utf-8") as csvfile: + reader = csv.DictReader(csvfile) # lit automatiquement l'en-tête pour définir les clés des dictionnaires + for row in reader: # lit les lignes suivantes, renvoyées sous forme de dictionnaires + print(row) + print(row[""]) +``` + +---- + +### Lire un CSV sans en-tête via dictionnaires + +Si votre fichier CSV ne contient pas de ligne d'en-tête, mais que vous souhaitez quand même définir des en-têtes à +associer aux colonnes, vous pouvez utiliser un `DictReader` et préciser un argument `fieldnames=` : + +```python {.numberLines} +import csv + +with open("example-file.csv", "r", encoding="utf-8") as csvfile: + reader = csv.DictReader(csvfile, fieldnames=["col1", "col2"]) # définit les en-têtes + for row in reader: # lit les lignes suivantes, renvoyées sous forme de dictionnaires + print(row) # renvoie un dictionnaire avec des clés "col1" et "col2" + print(row["col1"]) +``` + +---- + +### Écrire un fichier CSV + +```python {.numberLines} +import csv + +# Créer une liste de listes pour imiter une feuille de calcul +rows = [] +for i in range(10): + rows.append([str(j + i) for j in range(10)]) + + +# Sous Windows, il faut préciser un argument newline à la fonction open, sinon +# chaque ajout de ligne causera deux passages à la ligne +with open("output.csv", "w", encoding="utf-8", newline="") as file: + writer = csv.writer(file, delimiter=";") + writer.writerows(rows) + +``` + +---- + +### Écrire un CSV avec des en-têtes + +```python {.numberLines} +headers = ["nom", "prenom"] +content = [ + {"nom": "Doe", "prenom": "John"}, + {"nom": "Smith", "prenom": "Jane"} +] + +with open("header-output.csv", "w", encoding="utf-8") as file: + # Initialiser le writer en précisant la liste des textes d"'en-tête + writer = csv.DictWriter(file, fieldnames=headers) + # Écrire la ligne d'en-tête + writer.writeheader() + # Écrire le contenu restant + writer.writerows(content) +``` + +Exemple avec un `DictWriter` diff --git a/documentation/09-sqlite.md b/documentation/09-sqlite.md new file mode 100644 index 0000000..9fd3d9c --- /dev/null +++ b/documentation/09-sqlite.md @@ -0,0 +1,270 @@ +--- +title: Le SQL avec SQLite3 +author: Steve Kossouho +--- + +# Premiers pas en SQL avec SQLite3 + +---- + +## DBAPI c'est quoi ? + +Python propose une API unifiée standardisée pour accéder à des bases de données SQL (_Structured Query Language_), nommée DBAPI. +Les objets et méthodes ont toujours les mêmes noms et le même usage. +Il existe plusieurs bibliothèques compatibles pour accéder à des systèmes différents. +La bibliothèque standard de Python propose une API compatible pour **SQLite3**. + +[**SQLite3**](https://www.sqlite.org/index.html) est un moteur de bases de données relationnelles au format fichier, facile à mettre en place, et adapté pour des logiciels de bureau (ex. Firefox l'utilise). Il n'est pas adapté pour être utilisé dans une application web en production, car il ne gère pas les rôles et droits, ni ne tolère les multiples connexions (en écriture notamment). + +---- + +## Manipuler une base avec DBAPI + +Pour travailler sur notre première base de données, nous allons découper l'exemple en quatre étapes. + +---- + +### Étape 1 : Se connecter à la base + +```python {.numberLines} +import sqlite3 + +connection = sqlite3.connect("intro.sqlite3", isolation_level=None) +connection.close() +``` + +Crée un nouveau fichier de base de données SQLite3, pour le moment vide. + +---- + +### Étape 2 : Créer un schéma de base + +On brode sur l'exemple précédent pour créer une nouvelle table. +Cette table ne possède pas de contrainte particulière et autorise à enregistrer des doublons +(mêmes prénom, nom et âge). + +```python {.numberLines} +import sqlite3 + +connection = sqlite3.connect("intro.sqlite3", isolation_level=None) +cursor = connection.cursor() # cet objet est utilisé pour envoyer des requêtes +cursor.execute(""" +CREATE TABLE IF NOT EXISTS person ( + id integer PRIMARY KEY AUTOINCREMENT NOT NULL, + nom varchar(30) NOT NULL, + prenom varchar(20) NOT NULL, + age int unsigned NOT NULL +)""") +connection.close() +``` + +---- + +### Étape 3 : Ajouter des données + +On ajoute ensuite quelques données dans notre nouvelle table : + +```python {.numberLines} +import sqlite3 + +# Requête d'insertion utilisant la notation QMark (protection contre injections) +PERSON_INSERT_QUERY = "INSERT OR IGNORE INTO person (id, nom, prenom, age) VALUES (NULL, ?, ?, ?)" + +connection = sqlite3.connect("intro.sqlite3", isolation_level=None) +cursor = connection.cursor() +... +cursor.execute(PERSON_INSERT_QUERY, ("Bouquet", "Carole", 63)) +cursor.execute(PERSON_INSERT_QUERY, ("Connery", "Sean", 80)) +cursor.execute(PERSON_INSERT_QUERY, ("Trintignant", "Jean-Louis", 53)) +connection.close() +``` + +---- + +### Étape 4 : Requêter et parcourir des résultats + +Comme pour les fichiers texte dans lesquels nous pouvons naviguer dans les lignes via une boucle `for`{.python}, +exécuter une commande SQL destinée à renvoyer des résultats autorise à parcourir l'objet de type `Cursor`{.python} via une boucle `for`{.python} pour récupérer des résultats : + +```python {.numberLines} +import sqlite3 + +connection = sqlite3.connect("intro.sqlite3", isolation_level=None) +cursor = connection.cursor() +... +# Exécuter une requête pour retrouver des données +cursor.execute("SELECT * FROM person WHERE age > 50") +for result in cursor: # s'arrête automatiquement quand il n'y a plus de résultat + print(result) # result est toujours un tuple correspondant à un résultat +connection.close() +``` + +---- + +### Bonus : Récupérer des résultats sous forme de dictionnaires + +Il est possible de configurer l'objet de connexion SQLite3 pour récupérer des objets de type `sqlite3.Row`{.python} : + +```python {.numberLines} +import sqlite3 + +connection = sqlite3.connect("demo.sqlite", isolation_level=None) + +# Configure la connexion pour que les requêtes renvoient des objets Row +connection.row_factory = sqlite3.Row +cursor = connection.cursor() +... + +cursor.execute("SELECT * FROM person WHERE age BETWEEN 20 AND 40") +for result in cursor: # type: sqlite3.Row + print(result, dict(result)) +connection.close() +``` + +Les objets de type `sqlite3.Row`{.python} sont utilisables comme des dictionnaires, et permettent ainsi d'extraire des résultats en utilisant les noms des colonnes. Ils sont aussi convertibles directement en dictionnaires. + + +---- + +## Hors-programme : Requêtes universelles avec les ORMs + +C'est bien d'envoyer du SQL à une base de données, mais le problème du standard SQL, c'est que +tous les systèmes de gestion de bases de données ne gèrent pas toujours le SQL de la même façon; +certains proposent leur propre syntaxe ou ne prennent pas en charge une partie du standard, etc… + +Sur un projet de taille moyenne, et même de taille modeste, si vous écrivez tout votre code SQL à la main, +basculer d'un _SGBDR_ à un autre (par exemple pour un passage en production) nécessitera +très probablement de retoucher ou d'adapter vos requêtes. + +---- + +Ce problème est, entre autres questionnements, à l'origine de l'existence des ORMs (`Object Relational Mapper`). +Ce sont des bibliothèques qui offrent une abstraction de la base de données et la remplacent par +l'écriture de code, non plus en SQL, mais dans votre langage **orienté objet** préféré, +pour représenter des schémas et manipuler vos données. + +---- + +Les ORMs font généralement usage des concepts suivants : + +| Objet | Correspond à... | +|--------------------|:----------------------------------------| +| Classe Modèle | Table de la base de données | +| Attribut de classe | Colonne d'une table | +| Instance de Modèle | Ligne d'une table de la base de données | + +En plus de cela, le même code peut être utilisé pour basculer d'un SGBD à un autre (s'il est pris +en charge par l'ORM). + +---- + +### Exemples d'ORMs Python connus : + +- [SQLAlchemy](https://www.sqlalchemy.org/) +- [Peewee](http://docs.peewee-orm.com/en/latest/) +- [Pony ORM](https://docs.ponyorm.org/toc.html) +- [Django ORM](https://docs.djangoproject.com/fr/3.2/topics/db/queries/) (framework web) + +---- + +## Bonus : Petite explication sur `isolation_level` + +Dans notre premier slide contenant du code, nous avons défini un argument facultatif à la fonction `connect`, nommé +`isolation_level`. Celui-ci permet de définir le [niveau d'isolation](https://en.wikipedia.org/wiki/Isolation_(database_systems)) des commandes SQL que l'on envoie. + +Si l'on passe la valeur `None`{.python} à cet argument, l'auto-commit est activé, ce qui signifie que nous n'avons plus besoin +d'appeler manuellement `commit()`{.python} lorsqu'on souhaite persister nos modifications. Ceci est normalement le comportement +par défaut pour toute bibliothèque DBAPI, mais pour une raison inconnue, cela n'est pas le cas pour `sqlite`. Le bug sera corrigé +dans Python 3.12. + +---- + +En temps normal, si nous n'avions pas précisé ce paramètre : + +- Ouvrir la connexion (sans autocommit) +- `connection.execute()`{.python} → ouvre une transaction +- `connection.execute()`{.python} +- `connection.execute()`{.python} +- Aucune modification n'est persistée tant qu'on n'appelle pas `connection.commit()`{.python} + +Le fait de devoir `cnx.commit()`{.python} par défaut n'est pas spécialement intuitif, notamment +lorsqu'on débute en bases de données... + +---- + +Grâce à notre paramètre `isolation_level`, le comportement est plus intuitif par défaut : + +- Ouvrir la connexion (avec autocommit) +- `connection.execute()`{.python} → modification immédiate +- `connection.execute()`{.python} → modification immédiate +- `connection.execute("BEGIN")`{.python} → Ouverture explicite d'une transaction +- `connection.execute()`{.python} → modification non persistée +- `connection.execute("COMMIT")`{.python} → ferme la transaction et applique les modifications si + possible + +---- + +## Bibliothèques Python compatibles DB API 2.0 : + +- MySQL : `pip install mysql-connector-python`{.shell} ([doc](https://dev.mysql.com/doc/connector-python/en/)) +- PostgreSQL : `pip install psycopg`{.shell} ([doc](https://www.psycopg.org/docs/)) +- SQL Server : `pip install pymssql`{.shell} ([doc](https://pymssql.readthedocs.io/en/stable/)) +- Oracle : `pip install cx_Oracle`{.shell} ([doc](https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html)) + +---- + +## Navigateur de bases de données intégré à Pycharm + +Vous pouvez naviguer dans vos bases de données graphiquement dans PyCharm +grâce à un plugin de l'IDE, nommé *Database Navigator*. + +Pour l'installer : + +1. Cliquez sur `File`, `Settings`, puis la section `Plugins`. +2. Cliquez sur l'onglet `Marketplace` +3. Juste en-dessous de l'onglet `Marketplace`, dans le champ de recherche, saisissez "Database" +4. Vous devriez voir `Database Navigator` apparaître dans les résultats. +5. En regard de ce résultat, cliquez sur `Install`. +6. Si l'installation fonctionne, cliquez en regard du résultat sur `Restart IDE` pour redémarrer PyCharm. + +---- + +### Configurer DB Navigator + +Si vous venez d'installer le plugin, vous devez révéler le panneau de l'extension. +Le plus simple est d'utiliser le menu de PyCharm pour le trouver : + +![Afficher DB Browser](assets/images/database-show-db-browser.png) + +---- + +Vous pouvez déplacer le panneau avec un clic droit sur sa barre de titre, puis en cliquant sur `Move`. +Cela vous permettra de ne pas masquer le panneau de projet lorsque vous travaillez sur votre base de données. + +---- + +### Configurer une base de données + +Dans le panneau DB Browser, cliquez sur l'icône d'ajout pour créer une configuration, puis choisissez SQLite. + +1. Dans l'onglet `Connections` et le sous-onglet `Database`, +2. Choisissez un nom à votre connexion. Il vous servira juste visuellement +3. Dans le tableau de l'option `Database files`, cliquez sur `sqlite.db`, puis cliquez sur le bouton qui apparaît au bout de la ligne de texte, afin de choisir le bon fichier de base de données SQLite à surveiller. +4. Dans l'onglet `Connections`, cliquez le sous-onglet `Details`, puis : +5. Réduisez toutes les options `Idle time...` à `1` +6. Décochez `Connect automatically` +7. Terminez la configuration en cliquant le bouton `OK`. + +---- + +Vous pouvez ensuite voir dans le panneau `DB Browser` que votre connexion est prête, dans une arborescence. +Cliquez sur le nœud principal de l'arborescence, puis cliquez sur `Connect` +(il faut se connecter à la base pour pouvoir en explorer le contenu) + +---- + +![Onglet Database](assets/images/database-configure-connection.png) + +---- + +![Onglet Details](assets/images/database-configure-connection-settings.png) diff --git a/documentation/10-graphical-ui-extra.md b/documentation/10-graphical-ui-extra.md new file mode 100644 index 0000000..e5cd6c2 --- /dev/null +++ b/documentation/10-graphical-ui-extra.md @@ -0,0 +1,146 @@ +--- +title: Interfaces graphiques avec Pyside +author: Steve Kossouho +--- + +# Développer avec Pyside et Qt Designer + +---- + +## Fichiers .ui et utilisation avec Python + +Nous avons vu précedemment comment concevoir graphiquement des fenêtres dans l'outil Qt Designer, +puis comment les exploiter dans notre code Python. Nous avons d'abord utilisé la classe `QUiLoader` +et récupéré un objet de type `QWidget` (généralement de type `QMainWindow` précisément). + +```python +from PySide6.QtUiTools import QUiLoader +from PySide6.QtWidgets import QApplication + +def button_slot(): + """Fonction utilisée comme slot.""" + pass + +if __name__ == '__main__': + app = QApplication() + window = QUiLoader().load("file.ui") + button = window.button + button.clicked.connect(button_slot) + window.show() + ... + app.exec() +``` + +---- + +### Problème de l'approche "non objet" + +Cette approche simple ne permet malheureusement pas de profiter de certaines fonctionnalités +essentielles. Par exemple, il n'est pas possible de définir des _slots_ via de simples fonctions dans lesquels +il serait possible de retrouver un widget qui a généré un _signal_. + +La raison principale à cette catégorie de problèmes provient du fait que l'application Qt est gérée via l'objet +`QApplication` dans un thread distinct. Ce thread n'est pas en mesure de transmettre certaines références au processus +principal de votre programme, notamment les références d'objets générant un signal. + +---- + +Le seul moyen correct de procéder (assez mal documenté) afin que votre code gérant vos widgets soit connecté au thread +de l'application Qt : Coder la gestion de votre fenêtre dans une classe héritant au moins d'une classe de la bibliothèque +Qt (ex. `QObject`). Hériter d'une telle classe vous offre d'ailleurs une méthode essentielle pour retrouver une référence +d'objet ayant généré un signal : `sender()` + +---- + +Voici un exemple de code correct important une conception graphique d'un fichier .ui : + +```python +from PySide6.QtCore import QObject, Slot +from PySide6.QtUiTools import QUiLoader +from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget + +class WindowManager(QObject): + """Classe gérant l'interface graphique et contenant des slots.""" + window: QMainWindow | QWidget = None + button: QPushButton = None + + def __init__(self, *args, **kwargs): + # Ligne nécessaire pour exécuter l'initiation du QObject + super().__init__(*args, **kwargs) + self.window = QUiLoader().load("fichier.ui") + self.button = getattr(self.window, "button") + # Configurer le clic sur le bouton peut être configuré dans Designer + self.button.clicked.connect(self.button_clicked) + + @Slot() # marquer correctement la méthode comme slot + def button_clicked(self): + """Slot du clic sur le bouton.""" + print(self.sender()) + +if __name__ == '__main__': + application = QApplication() + manager = WindowManager() + manager.window.show() + application.exec() +``` + +---- + +Dans l'exemple précédent, plusieurs éléments importants ont été rigoureusement respectés : + +- La classe de gestion de l'interface et des slots hérite de `QObject` au moins; +- les slots sont décorés par la classe `Slot`, qui possède une méthode `__call__` renvoyant un décorateur (parenthèses nécessaires); + +---- + +## Utiliser des widgets personnalisés dans Designer + +Supposons que vous avez rédigé du code pour créer votre propre widget (soit personnellement dessiné soit composé d'autres sous-widgets). +Vous souhaitez utiliser Qt Designer pour concevoir votre interface, faisant usage dudit widget. + +Malheureusement pour vous, seuls les widgets standard proposés par la bibliothèque Qt seront disponibles dans la boîte à outils +de Qt Designer. Heureusement, il est possible de personnaliser votre conception pour intégrer vos propres classes de widgets. +Pour cela vous devez insérer dans l'interface un widget duquel hérite votre classe personnalisée (ex. `QFrame`) puis le "**promouvoir**". + +---- + +Pour cela, sélectionnez votre widget dans l'interface d'aperçu ou dans l'explorateur d'objet avec un clic droit. +Cliquez ensuite sur l'option `Promouvoir en…`. Une boîte de dialogue listant les widgets déjà promus s'affichera et vous proposera +de promouvoir le widget que vous venez de sélectionner. + +![Promotion de widget](assets/images/gui-qtdesigner-widget-promotion.png) + +---- + +Vous devez sélectionner la classe de widget de base (probablement celle déjà utilisée pour le widget à promouvoir), +puis indiquer le nom de la classe de widget à utiliser à l'exécution. Le nom du fichier d'en-tête n'est utilisé que pour +le langage C++, donc vous pouvez y saisir un point (`.`). + +---- + +Une fois le fichier .ui regénéré, il vous faudra configurer votre objet `QUiLoader` pour y enregistrer les classes de +widgets personnalisées : + +```python +from PySide6.QtUiTools import QUiLoader +from mymodule import MyWidgetClass + +loader = QUiLoader() +# Register custom widget class so that the promoted widget works. +loader.registerCustomWidget(MyWidgetClass) +widget = loader.load("fichier.ui") +``` + +Au chargement du fichier XML, les références du nom de classe généreront correctement les instances du type approprié. +Notez que si votre classe de widget définit des propriétés supplémentaires par rapport à la classe dont elle hérite, +vous pouvez les ajouter et les initialiser dans le panneau de l'_éditeur de propriétés_ de Qt Designer. + +---- + +## CSS dans les widgets +### Propriétés CSS +### Appliquer correctement son CSS +### Appliquer depuis un fichier +## Ressources +### Créer une ressource +### Compiler une ressource diff --git a/documentation/10-graphical-ui.md b/documentation/10-graphical-ui.md new file mode 100644 index 0000000..90cb5dc --- /dev/null +++ b/documentation/10-graphical-ui.md @@ -0,0 +1,251 @@ +--- +title: Faire sa première interface graphique +author: Steve Kossouho +--- + +# Faire sa première interface graphique avec Python + +---- + +## Exemples d'outils pour les interfaces graphiques + +Depuis la moitié des années 80, on a commencé à voir s'introduire dans le domaine public des +ordinateurs livrés avec des interfaces graphiques, destinées à interagir simplement avec le système. +Avec le temps, les outils de programmation se sont peaufinés, au point qu'à ce jour, il existe de +très nombreux outils avancés de développement pour créer des interfaces graphiques, même avec Python. + +Parmi eux, on rencontre fréquemment : + +- [Qt](https://www.qt.io/) (PyQt ou PySide) +- [GTK](https://www.gtk.org/) (Python-GTK) +- [tkinter](https://docs.python.org/fr/3/library/tkinter.html) (bibliothèque standard) +- [wxWidgets](https://www.wxwidgets.org/) (wxPython) + +---- + +### Choix de la communauté + +Parmi les choix disponibles pour créer des interfaces, les développeurs utilisent très fréquemment +la bibliothèque Qt, de par la relative intuitivité de l'API que cette dernière propose. Également, +elle est fournie avec de nombreuses applications très utiles pour concevoir ses applications, qui +fonctionnent d'ailleurs assez bien sur de nombreux systèmes d'exploitation, comme Windows, +Linux ou encore Mac OS. + +---- + +### L'interface par défaut de Tkinter + +![Tkinter sous Ubuntu](assets/images/gui-api-tkinter.png) + +(_Il est possible d'appliquer des thèmes qui imitent un thème, comme Win XP, Win 10, etc._) + +---- + +### Exemple simple d'application Linux avec PySide + +![PySide sous Windows, Linux, Mac OS](assets/images/gui-api-pyside.png) + +---- + +### Choix de bibliothèque pour la formation + +Pour ce chapitre, nous allons utiliser la bibliothèque Qt. Avec Python, nous avons accès à plusieurs +bibliothèques qui calquent l'API proposée par la bibliothèque originale en C++, telles que `PyQt` ou +`PySide`. + +Pour des raisons de prise en charge officielle (de contenu packagé, et probablement de licence), +le choix se porte depuis quelques années sur `PySide`. + +- [Documentation de PySide](https://wiki.qt.io/PySideDocumentation) +- [Exemples PySide](https://wiki.qt.io/PySide_Example_Applications) + +---- + +## PySide6 avec Python (sous Linux et Windows) + +En principe, pour travailler avec PySide sous Windows et Linux, il vous suffira d'installer le +paquet avec l'outil `pip`, aucun autre téléchargement ne semble être requis. + +(Une intégration du thème des applications GTK dans PySide nécessite souvent d'utiliser le paquet +`pyside` installable via le gestionnaire de paquets de votre distribution Linux, et d'installer +également une bibliothèque pour Qt destinée à imiter les thèmes GTK.) + +---- + +## Installer PySide avec pip + +```{.bash .numberLines} +pip install pyside6 # environ 200 Mo +``` + +La commande installe la bibliothèque précompilée pour votre système d'exploitation, avec des programmes de gestion +inclus (**Qt Designer**, **Qt Resource Compiler**, etc.). + +---- + +## Écrire une fenêtre simple + +Pour afficher sa première application fenêtrée avec PySide, nous **devons** suivre quelques directives : + +- Créer un objet `QApplication` (singleton). Il gère notre application Qt. +- Tous les widgets "vivront" automatiquement dans cet objet d'application. + +```{.python .numberLines} +from PySide6.QtWidgets import QApplication, QMainWindow + +if __name__ == "__main__": + application = QApplication() + window = QMainWindow() + window.show() # Affiche la fenêtre + application.exec() # essayez sans cette ligne... +``` + +---- + +## Concepts des interfaces graphiques Qt + +Pour pouvoir parcourir plus en détail l'univers de **Qt**, il nous faut aborder certains concepts nécessaires pour un projet +complet autour de la bibliothèque : + +- `Signal` : représente un type d'événement disponible sur un widget, ex. _cliqué_, _texte modifié_, etc. +- `Slot` : fonction exécutable lorsqu'un `Signal` est émis. +- `Property` : attribut d'un widget défini sous forme de méthodes, ex. `QMainWindow.windowTitle` + +---- + +## Concevoir graphiquement une fenêtre et l'utiliser avec Python + +Il existe des outils graphiques pour concevoir vos fenêtres, et vous pouvez ensuite importer votre travail +dans vos propres applications Python, ce qui vous permet de ne vous occuper que du code métier (ou presque). + +Lorsque vous installez `PySide` avec `pip`, le package vous propose en ligne de commande d'utiliser +l'application **Qt Designer**, un outil visuel qui vous aide à créer vos fenêtres et boîtes de dialogue. + +```{.bash .numberLines} +pyside6-designer & # lancer l'outil depuis un terminal… retirez le "&" sous Windows +``` + +---- + +### Interface principale de Qt Designer + +![Qt Designer en action](assets/images/gui-qtdesigner.png) + +---- + +#### Zone principale + +Lorsque vous utilisez Qt Designer, vous obtenez une interface **WYSIWYG** (What You See Is What You Get), +vous permettant de configurer visuellement et précisément un widget (qu'il s'agisse d'une fenêtre ou d'autre chose). + +Vous pouvez y sélectionner, redimensionner ou "reparenter" un widget. C'est beaucoup plus facile que +de le faire à la main. Vous pouvez également y déposer de nouveaux widgets en effectuant un glisser-déposer depuis la **Boîte de widget**. + +Note : Vous pouvez aussi générer du code Python via l'outil, mais il est assez inélégant. + +---- + +#### Inspecteur d'objet + +Le panneau d'inspecteur d'objet vous montre deux informations : + +1. L'arborescence des widgets contenus dans votre fichier actuel; +2. Chaque élément est affiché sur deux colonnes, d'abord le nom du widget (ex. `pushButton`), puis son type (ex. `QPushButton`). + +Il peut être utile pour sélectionner facilement un widget, par exemple lorsque ce dernier est difficile à sélectionner +avec la souris dans la zone d'aperçu. + +---- + +#### Éditeur de propriétés + +L'éditeur de propriétés est un panneau traditionnel (comme dans Visual Basic 4) affichant la liste des propriétés disponibles sur un widget, par exemple ses _dimensions_, la _police de caractères à utiliser_, le _texte du bouton_ etc… + +Les propriétés sont souvent disponibles à la fois en lecture et en écriture, mais certaines peuvent n'exister +que pour consulter un état d'un widget (lecture seule). + +---- + +### Générer un script Python depuis Qt Designer + +L'outil Qt Designer permet de générer des fichiers Python qui construisent votre fenêtre. Vous pouvez par la suite utiliser +le code généré dans votre projet Python (même s'il y a mieux à faire). + +TODO: Ajouter une capture d'écran + + +---- + +### Charger un widget enregistré au format .ui + +Les fichiers `.ui` générés par Qt Designer sont en réalité des fichiers XML indiquant l'arborescence de l'interface et +les propriétés à définir sur les widgets. + +Également, ces fichiers contiennent des informations supplémentaires, comme les fichiers de ressources associés, mais +pour le cadre de la formation, nous ne sommes pas obligés de nous y intéresser. (ça peut attendre) + +TODO: Promotion, Custom Signals et Slots, Ajout de propriétés etc. + +```{.python .numberLines} +from PySide6.QtUiTools import QUiLoader + +# N'oubliez pas l'application, naturellement +window = QUiLoader().load("fichier.ui") # QMainWindow +``` + +---- + +## Interagir avec les contrôles + +PySide propose un système simple de signaux (événements) et slots (fonctions cibles), qui permettent +de réagir lorsque des événements se produisent sur des widgets. + +Pour associer au clic sur un bouton l'exécution d'une fonction, nous devons utiliser +une méthode `connect` sur une référence qui porte le nom d'un événement, par exemple `clicked` : + +```{.python .numberLines} +from PySide6.QtWidgets import QPushButton + +def some_function_reference(): + pass + +button = QPushButton() +button.clicked.connect(some_function_reference) +``` + +Notez que PyCharm ne peut pas autocompléter `connect` à cause de la nature de la bibliothèque +(écrite en C++, avec des _stubs_ incomplets pour Python). +Ce problème semble ne pas pouvoir être résolu ni du côté de **JetBrains**, ni du côté de **Microsoft**. +Il semble qu'il pourrait être résolu du côté de **Qt**, qui refuse de corriger ses stubs Python… + +---- + +## Qt Designer : mise en page adaptée au redimensionnement de fenêtre + +Sous Qt Designer (ou QtCreator), aucun moyen simple n'a l'air disponible pour associer un layout +au widget central d'une fenêtre (c'est-à-dire, un widget de mise en page qui possède toujours les mêmes +dimensions que la fenêtre)… + +Ça n'est pas intuitif, mais y parvenir est beaucoup plus simple qu'il n'y paraît. + +---- + +![Fenêtre avec un layout non redimensionné](assets/images/gui-qtdesigner-layout-1.png) + +---- + +- Vous pouvez cliquer droit dans un espace vide de la fenêtre, et ajouter un layout au **widget central** : + + - Allez sur le menu contextuel `Mettre en page` (ou `Lay out`); + - Puis choisissez le layout utilisé pour le widget central (généralement `QGridLayout`); + - Tous les éléments qui étaient présents dans le widget central vont se disposer dans le nouveau layout. + +- Vous pouvez aussi sélectionner le widget central dans l'inspecteur puis cliquer sur un bouton de layout dans la barre d'outils de l'application. + +Le layout étant associé au widget central de la fenêtre, il se redimensionnera avec la fenêtre. + + + +---- + +![Tout mettre dans un layout associé au widget central](assets/images/gui-qtdesigner-layout-2.png) diff --git a/documentation/11-code-documentation.md b/documentation/11-code-documentation.md new file mode 100644 index 0000000..41d3f8f --- /dev/null +++ b/documentation/11-code-documentation.md @@ -0,0 +1,193 @@ +--- +title: Documenter du code Python +author: Steve Kossouho +--- + +# Documenter du code Python + +---- + +## Documenter du code ? + +En Python, comme dans d'autres langages, vous savez que l'on peut introduire des commentaires dans le code. +Il suffit d'utiliser le symbole `(#)` dans une ligne de code, et ce qui suit sera considéré comme commentaire. + +Mais saviez-vous que Python considère le concept de documentation comme étant à part ? + +---- + +```{.python .numberLines} +print(__doc__) # Ne provoque pas d'erreur, mais affiche `None` +``` + +Les modules, packages, classes, fonctions et méthodes sont toujours, lorsque vous exécutez l'interpréteur Python, +équipés d'attributs nommés `__doc__`. (C'est l'interpréteur qui ajoute l'attribut automatiquement, entre autres +fonctionnements magiques) +Tout module possède implicitement une variable `__doc__` disponible dans son namespace/scope. +Cet attribut « magique » laisse entendre que la notion de documentation fait partie intégrante du langage Python. + +---- + +### Documentation dans la bibliothèque standard + +```{.python .numberLines} +import sqlite3 + +print(sqlite3.__doc__) # documentation du module SQLite3 +``` + +Ici, on importe un module écrit par un développeur tiers, pour voir si l'on est capable de +récupérer quelque chose dans son attribut `__doc__`{.python}. + +---- + +## Comment on fait pareil qu'eux ? + +Pour documenter un module, c'est finalement assez simple : + +```{.python .numberLines} +"""Texte de documentation du module.""" +import os, sys +print(os.linesep, sys.getwindowsversion()) +``` + +Il faut, en première instruction du module, écrire une chaîne de caractères. Par convention, il faut écrire une chaîne à trois guillemets. En Python, on appelle cela une docstring. (consultez PEP8 docstrings) + +---- + +## Qu'est-ce qu'on peut documenter ? + +On peut documenter pas mal de choses avec cette méthode : + +1. Modules et packages; +2. fonctions et méthodes; +3. classes. + +Les variables ne sont pas documentables directement : elles +récupèrent automatiquement la **documentation de leur classe**. + +---- + +## Qu'est-ce qu'on met ? + +Pour documenter, par exemple, un module, il y a deux façons de faire : + +1. Si votre documentation tient en une phrase courte. +2. Si votre documentation va contenir davantage de texte. + +---- + +### Documentation super courte + +Vous pouvez considérer qu'une seule petite phrase peut servir à décrire votre module : + +```{.python .numberLines} +"""Traitement des données d'épuration des eaux.""" +``` + +---- + +### Documentation plus longue + +```{.python .numberLines} +""" +Traitement des données d'épuration des eaux. + +Paragraphes de description, d'explication du contenu du module. +Possibilité d'ajouter des sections, des exemples, soyez exhaustifs si vous le souhaitez ! +""" +``` + +- Une phrase courte de résumé, sur sa propre ligne. +- Une ligne vide. +- Le corps de la documentation. + +---- + +## Documenter une classe, fonction, méthode, package + +- Pour documenter une classe, il suffit d'ajouter une docstring, juste en-dessous de la signature de la classe. +- Pour une fonction, ajoutez vos triples guillemets en-dessous de la signature de méthode/fonction. +- Pour un package, mettez une docstring au sommet du module `__init__.py` + +---- + +## Outils de génération de documentation HTML etc. + +Mieux qu'un long discours, une démo s'impose, avec la bibliothèque `pdoc`. +Un outil beaucoup plus long à mettre en place est `sphinx`, qui permet encore davantage. + +```{.bash .numberLines} +pip install pdoc # installer la bibliothèque +pdoc [nom du module ou nom du script python] # lance un serveur pour tester +``` + +- [Documentation de pdoc](https://pdoc.dev/docs/pdoc.html) +- [Documentation de Sphinx](https://www.sphinx-doc.org/en/master/) + +---- + +## Bonus : Donner des indications sur le type des variables et arguments + +Depuis Python 3.5 (fin 2015), le langage propose un moyen d'indiquer aux développeurs, le type attendu de variables et d'arguments de fonctions. + +**Attention cependant** : les indications en question n'ont aucune incidence sur l'exécution du code, c'est-à-dire que l'interpréteur les ignore. Par contre, les développeurs et les environnements de développement, eux, peuvent se servir de ces indications pour proposer de l'autocomplétion dans certains cas. + +---- + +Pour annoter une variable et définir quel est son type attendu, on peut : + +```{.python .numberLines} +from tartempion import MyClass + +variable1: int = 15 # on indique qu'on attend un entier +variable2: str = "Hello" # on attend une chaîne +variable3: list = [] # on attend une liste +object1: MyClass = MyClass() # on attend un objet d'une classe +``` + +Un éditeur (tel que PyCharm) ou un outil de vérification en ligne de commande saura vous dire +si ailleurs dans votre code, vous ne respectez pas ces indications. + +---- + +Le module `typing` de la bibliothèque standard permet de décrire de façon plus avancée des types attendus : + +```python {.numberLines} +from typing import Optional, Union, Any, Literal, Callable + +variable: Optional[int] = None # on attend `None` ou un entier +multi_types: Union[int, float] = 25 # on attend un entier ou float +collection: list[str] = [] # ne fonctionne que dans Python 3.9+ +shapeshifter: Any = [] # tout et n'importe quoi, explicitement +finite_values: Literal["Monday", "Tuesday"] = "Monday" # Valeurs finies +function_reference: Callable = range # on attend une fonction +``` + +À partir de Python 3.11 (novembre 2022), il est possible de remplacer l'`Union` par un opérateur `|` : + +```{.python .numberLines} +variable: int | float = 15 # soit un entier soit un flottant devrait y être associé +``` + +[Section de la documentation officielle de Typing](https://docs.python.org/3/library/typing.html#module-contents) + +---- + +On peut faire la même chose avec des arguments de fonctions : + +```{.python .numberLines} +# value et default devraient être des entiers +def do_some_important_things(value: int, default: int = 1): + print(value, default) + return None +``` + +---- + +Et on peut également décrire le type attendu du retour des fonctions et méthodes : + +```{.python .numberLines} +def do_trivial_things() -> float: # on indique que la fonction retourne un flottant + return 100 / 15 +``` diff --git a/documentation/12-logging.md b/documentation/12-logging.md new file mode 100644 index 0000000..6147d79 --- /dev/null +++ b/documentation/12-logging.md @@ -0,0 +1,275 @@ +--- +title: Journalisation d'événements +author: Steve Kossouho +--- + +# Journaliser des événements en Python + +---- + +## Journaliser ? + +Lorsque l'on exécute un programme au long cours, souvent un service, un serveur ou même une application graphique, +il est souvent important de pouvoir retracer ce qui s'est produit avant qu'une exception soit levée, ou qu'un comportement +inattendu montre le bout de son nez. + +---- + +La journalisation est un outil formidable à cet effet, puisqu'elle vous permet de consigner, dans la console ou tout +autre support, une liste chronologique de messages et d'événements que vous pouvez retracer _a posteriori_. Pour peu +que vous consigniez assez de messages, ils peuvent être capitaux, ne serait-ce que pour fournir du support à +vos utilisateurs. + +---- + +## À quoi ça ressemble ? + +La journalisation est sensiblement identique sur tous les systèmes. Vous consignez des messages avec des niveaux de sévérité divers. + +En voici un exemple arbitraire : + +```log +2021-01-01 23:51:15 - DEBUG - Logging message 3 +2021-01-01 23:51:10 - DEBUG - Logging message 2 +2021-01-01 23:50:37 - WARNING - Logging message 1 +``` + +---- + +Un administrateur ou un outil peuvent consulter ce genre de fichier +pour en savoir plus sur leur système. En marquant les messages comme possédant un niveau de sévérité, il est aussi possible de voir +rapidement quels messages doivent être traités en priorité. + +---- + +Les niveaux de sévérité d'un système de journalisation sont les suivants : + +- `DEBUG` : Pour les développeurs, remplace le `print`. +- `INFO` : Information standard (version, action effectuée etc.) +- `WARNING` : Attention à porter à un problème potentiel. +- `ERROR` : Une erreur s'est produite, gênante pour les utilisateurs. +- `CRITICAL` : Une erreur irrécupérable à corriger immédiatement s'est produite. + +---- + +## Le module `logging` + +La bibliothèque standard de Python propose un module, qui semble inspiré d'une API C++ ou Java (typographie) et qui offre +les outils nécessaires à organiser une bonne journalisation. + +---- + +```{.python .numberLines} +import logging + +logger = logging.getLogger(__name__) +``` + +Récupère le logger portant le nom du module en cours. Attention, si le module est celui que vous avez lancé spécifiquement, la variable +`__name__` (ou l'attribut `__name__` du module) prendra la valeur `"__main__"`. + +---- + +```{.python .numberLines} +import logging + +logger = logging.getLogger(__name__) +logger.log(logging.WARNING, "Message.") +logger.warning("Same message as before.") +``` + +Consignation de nouveaux messages. + +---- + +## Système de loggers + +Un logger est un objet que vous utilisez pour consigner de nouveaux messages dans votre système. Cet objet doit être associé à un ou plusieurs objets de type `handler`, qui sont des canaux de sortie pour le logger. + +---- + +## Hiérarchie des loggers + +Les loggers portent tous un nom. Le système de journalisation de Python fonctionne avec un système de hiérarchie, où le nom d'un logger définit où il se trouve dans la hiérarchie. Un message consigné par un logger est transmis à son logger parent, jusqu'au logger racine. +
+ +---- + +![Exemple de configuration](assets/images/logging-hierarchy.png) + +---- + +Dans l'exemple précédent, + +* Un message consigné avec le logger nommé `data.excel` remonte jusqu'au au logger racine. +* Tous les handlers associés aux loggers rencontrés en remontant la hiérarchie sont utilisés pour traiter le message. +* Si aucun handler n'a été rencontré après être arrivé au sommet, le handler de dernier recours (`lastResort`) est utilisé pour consigner l'événement. +* Ce handler affiche les messages de sévérité `>= logging.WARNING`{.python} dans la console d'erreur (rouge). + +---- + +## Utiliser les handlers + +Le clou du spectacle consiste à configurer des handlers pour les associer à des loggers. Pour configurer correctement un handler, il nous faut définir : + +- Son type (sortie fichier, console); +- Le format textuel des événements consignés; +- Son niveau de sévérité minimum pour accepter des messages. + +---- + +### Configuration d'un handler + +```{.python .numberLines} +import logging +handler = logging.FileHandler("filename.log", encoding="utf-8") +# Chaîne de formatage des événements +formatting = logging.Formatter("%(asctime)s - %(message)s") +handler.setFormatter(formatting) +# Le handler acceptera tous les messages >= DEBUG +handler.setLevel(logging.DEBUG) +``` + +[Référence des spécifieurs pour le format de texte](https://docs.python.org/3/library/logging.html#logrecord-attributes) + +---- + +## Types de handlers + +Les types de handlers disponibles sont disponibles ici : + +- `logging.FileHandler` : sérialise dans un fichier ([documentation](https://docs.python.org/3/library/logging.handlers.html#filehandler)). +- `logging.StreamHandler` : sérialise dans un flux, généralement console (voir slide suivant). +- `logging.handlers.*` : handlers plus avancés, dont fichiers avec rotation. + +[Handlers supplémentaires](https://docs.python.org/3/library/logging.handlers.html) + +---- + +## Types de flux console + +Pour les handlers vers un flux, voici la liste des flux classiques disponibles : + +- `sys.stdout` : sortie console normale. +- `sys.stderr` : sortie console d'erreur (affiché en rouge). + +*(voir le slide suivant pour l'utilisation de ces flux)* + +---- + +## Ajouter un handler à un logger + +Une fois un handler configuré, vous pouvez l'associer à un logger (puisque c'est sur le logger que vous allez utiliser des méthodes de journalisation). + +```{.python .numberLines} +import logging +import sys + +logger = logging.getLogger("logger.name") +handler = logging.StreamHandler(sys.stdout) +# Imaginons que l'on configure notre handler correctement +# (ici, il manque un format à spécifier) +# On peut *ajouter* notre handler à notre logger +logger.addHandler(handler) +``` + +---- + +Un logger peut également définir son propre niveau minimal de sévérité, qui sera utilisé pour potentiellement limiter la portée de ses handlers. + +```{.python .numberLines} +import logging +import sys + +logger = logging.getLogger("logger.name") +handler = logging.StreamHandler(sys.stdout) # il faudrait spécifier un format +logger.addHandler(handler) +# Limiter tous les handlers associés au niveau WARNING +logger.setLevel(logging.WARNING) +``` + +---- + +## Le logger racine + +Le logger racine est souvent utilisé pour configurer une journalisation globale pour toute votre application, puisque tout logger remonte toujours ses messages vers celui-ci. + +Pour le configurer, utilisez la variable `root` du module `logging` : + +```{.python .numberLines} +import logging +# Exemple minimaliste +handler = logging.FileHandler("filename") +# Tous les loggers vont passer par ce handler +logging.root.addHandler(handler) +``` + +---- + +## Récapitulatif minimal + +```{.python .numberLines} +import logging + +# Les 3 types d'objets nécessaires à la configuration +logger = logging.getLogger("myname") # nouveau logger nommé "myname" +handler = logging.FileHandler("myfile.log", encoding="utf-8") # handler fichier +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") # format de messages + +# Configuration du handler +handler.setFormatter(formatter) # configurer le handler +handler.setLevel(logging.DEBUG) # niveau de sévérité minimum + +# Configuration du logger +logger.addHandler(handler) # ajouter le handler au logger +logger.setLevel(logging.INFO) # niveau de sévérité minimum du logger +``` + +---- + +### Exemple de logger à deux handlers + +![Exemple d'usage d'un logger](assets/images/logging-building.png) + +--- + +## Plus : Fichier de configuration + +On peut configurer sa journalisation et créer d'une traite un ensemble de `loggers` via un fichier +de configuration (il est possible d'utiliser un dictionnaire), qui +sera stocké sous la forme d'un fichier ini. Le contenu à insérer dans ce fichier est décrit dans la section +[Configuration file format](https://docs.python.org/3/library/logging.config.html#configuration-file-format) +de la documentation Python. + +Les fichiers **ini** ont une structure qui est toujours de la forme : + +```ini +[section1] +property1 = value +property2 = value + +[section2] +property3 = value +``` + +---- + +### Charger un fichier de configuration + +Lorsque vous avez défini un fichier de configuration avec tous ses `loggers`, `handlers` et +`formatters`, vous pouvez l'utiliser via la fonction [`logging.config.fileConfig()`](https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig) : + +```{.python .numberLines} +from logging.config import fileConfig + +# Initialiser des loggers depuis une fonction +# Le fichier devrait être stocké dans un dossier à l'arborescence bien +# choisie. +fileConfig("logging.conf.ini", disable_existing_loggers=False, encoding="utf-8") +``` + +---- + +## Bibliothèques simplifiées de journalisation + +- [Loguru](https://loguru.readthedocs.io/en/stable/overview.html) diff --git a/documentation/99-base-magic-methods.md b/documentation/99-base-magic-methods.md new file mode 100644 index 0000000..c19bee9 --- /dev/null +++ b/documentation/99-base-magic-methods.md @@ -0,0 +1,129 @@ +--- +title: Classes et méthodes magiques +author: Steve Kossouho +--- + +# Personnalisation des classes + +En Python, une classe peut être considérée comme un plan pour créer des objets. Cependant, il est possible de personnaliser le comportement de ces classes de plusieurs manières. Cette personnalisation peut inclure la définition de méthodes spéciales pour gérer le cycle de vie des objets, ainsi que la conversion d'objets en chaînes pour un affichage plus lisible. + +---- + +## Méthodes pour gérer le cycle de vie d'un objet + +Dans le cycle de vie d'un objet, il existe plusieurs points clés où nous pouvons intervenir. +Ce sont la création de l'objet (via un constructeur), son initialisation (via un initialiseur), et sa destruction (via un destructeur). + +---- + +### Écrire un constructeur + +En Python, le constructeur est une méthode spéciale qui est utilisée pour créer les objets. +Il est défini en déclarant dans une classe la méthode spéciale `__new__`. + +```python +# Exemple d'une classe avec un constructeur +class Personne: + def __new__(cls, nom, age): + instance = super().__new__(cls) + instance.nom = nom + instance.age = age + return instance +``` +Dans cet exemple, le constructeur `__new__` prend trois paramètres : `cls` (la classe elle-même), `nom` et `age`. `cls` est l'objet sur lequel la méthode de classe a été appelée, tandis que `nom` et `age` sont des arguments passés lors de la création d'une instance de la classe. + +```python +# Création d'une instance de la classe Personne +p = Personne("John", 20) +``` + +---- + +### Écrire un initialiseur + +En Python, l'initialiseur est une méthode spéciale utilisée pour initialiser les objets. Il est défini en utilisant le mot-clé `__init__`. + +```python +# Exemple d'une classe avec un initialiseur +class Voiture: + def __init__(self, marque, modele): + self.marque = marque + self.modele = modele +``` +Ici, nous avons une classe `Voiture` avec un initialiseur qui initialise les variables d'instance `marque` et `modele`. + +```python +# Création d'une instance de la classe Voiture +v = Voiture("Tesla", "Model 3") +``` + +---- + +### Écrire un destructeur + +En Python, le destructeur est une méthode spéciale qui est utilisée pour nettoyer les ressources. Il est défini en utilisant le mot-clé `__del__`. + +```python +# Exemple d'une classe avec un destructeur +class Fichier: + def __init__(self, nom): + self.fichier = open(nom, 'r') + + def __del__(self): + self.fichier.close() +``` +Dans cet exemple, nous avons une classe `Fichier` qui ouvre un fichier lors de sa création et le ferme lors de sa destruction. + +```python +# Utilisation de la classe Fichier +f = Fichier("mon_fichier.txt") +del f # Ceci appelle le destructeur et ferme le fichier +``` + +---- + +## Méthodes pratiques de conversion d'un objet + +Il peut souvent être utile de convertir nos objets en chaînes, que ce soit pour un affichage plus lisible pour les utilisateurs (méthode `__str__`) ou pour une représentation qui peut être utilisée pour recréer l'objet (méthode `__repr__`). + +---- + +### Méthode `__str__` + +La méthode `__str__` en Python représente la classe sous une forme qui peut être lisible par l'utilisateur. Elle est appelée par la fonction `str()` et implicitement utilisée par la fonction `print()`. + +```python +# Exemple d'une classe avec la méthode __str__ +class Personne: + def __init__(self, nom, age): + self.nom = nom + self.age = age + + def __str__(self): + return f"Personne: {self.nom}, Age: {self.age}" + +p = Personne("John", 20) +print(p) # Affiche "Personne: John, Age: 20" +``` + +---- + +### Méthode `__repr__` + +La méthode `__repr__` en Python représente la classe sous une forme qui peut être utilisée pour recréer l'objet. Elle est appelée par la fonction `repr()`. + +```python +# Exemple d'une classe avec la méthode __repr__ +class Personne: + def __init__(self, nom, age): + self.nom = nom + self.age = age + + def __repr__(self): + return f"Personne('{self.nom}', {self.age})" + +p = Personne("John", 20) +print(repr(p)) # Affiche "Personne('John', 20)" +``` + +Dans cet exemple, `repr(p)` renvoie une chaîne qui montre l'expression à écrire dans du code pour recréer l'objet `p`. diff --git a/documentation/99-github-repository.md b/documentation/99-github-repository.md new file mode 100644 index 0000000..f014b36 --- /dev/null +++ b/documentation/99-github-repository.md @@ -0,0 +1,27 @@ +--- +title: Exercices et démos Github +author: Steve Kossouho +mainfont: JetBrains Mono +--- + +# Github formation + +Pour la formation Python initiation et approfondissement, j'ai créé un dépôt Github. +Le dépôt contient une liste d'exercices pour les sujets abordés dans la semaine : + +[Dépôt Github formation](https://github.com/sk-dwtoulouse/python-initiation-training/tree/main/exercices) + +---- + +## Github démos de code + +Vous trouverez aussi des démos de code sur des sujets que l'on a vus ou abordés, mais avec un code légèrement plus +avancé/propre : + +[Dépôt Github Démos](https://github.com/sk-dwtoulouse/python-initiation-training) + +---- + +## Sites d'exos ou tutos Python + +- https://data-flair.training/blogs/ diff --git a/documentation/99-more-imports.md b/documentation/99-more-imports.md new file mode 100644 index 0000000..102ccec --- /dev/null +++ b/documentation/99-more-imports.md @@ -0,0 +1,179 @@ +--- +title: Les imports +author: Steve Kossouho +--- + +# Plus d'imports + +---- + +## Packages et modules + +Nous avons vu comment créer packages et modules dans le tronc principal de la formation, mais ça vaut toujours le coup +d'en préciser un peu plus sur le concept. Pour rappel : + +- **Module** : Un fichier Python contenant (ou pas) du code. +- **Package** : Un répertoire contenant un fichier Python portant le nom `__init__.py` + +L'intérêt du concept de package pour les développeurs est de pouvoir ranger du code en arborescence. + +---- + +Du point de vue de l'interpréteur Python, les modules et packages sont tous des objets de type `module` : ce sont des +objets qui contiennent du code. La différence se trouve au niveau du développeur : + +- Les packages auront leur code représenté dans leur fichier `__init__.py`, +- Les modules étant des fichiers, leur code se trouve directement à l'intérieur, + +(1/2) + +---- + +- Les packages peuvent contenir d'autres packages et modules, et permettent d'organiser du code dans une arborescence, +- Tous les modules et packages à l'intérieur d'un package sont accessibles comme des attributs de l'objet représentant le package, en plus de ce qui est défini dans le fichier `__init__.py`. + +(2/2) + +---- + +## L'import de modules en mémoire + +Lorsque vous faites un import en Python, l'interpréteur va chercher dans la bibliothèque standard +(et ailleurs si possible) ce que vous lui demandez d'importer. L'outil se comporte d'une façon similaire à +la suivante : + +```python +from csv import DictReader +reader = DictReader([]) +``` + +---- + +- Python cherche un module/package `csv` dans le répertoire courant; +- Python cherche le module/package `csv` dans les dossiers de `PYTHONPATH`; +- Dans le répertoire `site-packages` de l'environnement virtuel, +- Puis la cherche dans la bibliothèque standard, etc. + +Si trouvé, `csv` est ajouté à un index interne des éléments déjà chargés en mémoire. +Pour importer quoi que ce soit depuis le module, le code entier du module devra être exécuté. +L'interpréteur ne donne ensuite accès qu'à `DictReader` au script qui l'a demandé. + +---- + +### Chargement et optimisation + +Lorsque l'interpréteur charge un module en mémoire, il garde une référence du module chargé (avec son chemin), de +façon à ce que si lors de l'exécution de votre programme vous venez à exécuter à nouveau un import du même module, +l'interpréteur optimise en ignorant votre commande : le module et son contenu sont déjà connus et en mémoire. + +Et heureusement : Si 20 modules de votre projet importaient le même module, beaucoup d'énergie et de temps serait perdus sans ce mécanisme. + +---- + +## Le PYTHONPATH + +Ce qu'on appelle le `PYTHONPATH`, est une variable d'environnement qui vous permet d'indiquer à un interpréteur +Python lancé en ligne de commande, que les imports peuvent être trouvés relativement à une liste de répertoires que vous +pouvez indiquer. Dans un terminal `bash` : + +```shell +export PYTHONPATH=/mon/repertoire:$PYTHONPATH +``` + +La commande est valide pendant l'exécution du terminal en cours. + +---- + +## Le PYTHONPATH dans PyCharm + +PyCharm est capable de configurer automatiquement pour vous le PYTHONPATH juste avant +d'exécuter vos scripts. Cela permet d'écrire des imports relatifs à l'arborescence de votre projet sans erreur. + +![Dialogue de configuration de lancement de scripts](assets/images/x-imports-pythonpath-pycharm.png) + +---- + +Cette boîte de dialogue contient deux cases à cocher, pour ajouter au `PYTHONPATH` vos dossiers de projet marqués comme +racines des sources ou de contenu. Pour marquer dans l'IDE un dossier comme étant un dossier racine des sources, il +suffit de se rendre dans l'arborescence du projet, cliquer droit sur un répertoire, choisir `Mark directory as`, puis +`Sources root`. + +---- + +## Les imports relatifs + +Lorsque vous faites des imports en Python, le langage vous offre une notation vous permettant d'effectuer +des imports dits relatifs. Le nom indique que depuis un module ou un package, vous pouvez importer un module qui se +trouve à un emplacement relatif : + +```text +- module_a.py +- module_b.py +- package_1/ + - submodule_1a.py +``` + +---- + +Si depuis `module_a`, je souhaite importer depuis `module_b`, je peux écrire par exemple (notez le point) : + +```python +from .module_b import symbol +``` + +Ce type d'import est pratique, mais provoquera une erreur dans un des cas suivants : + +- Votre module ne se trouve pas dans un package (son chemin ne contient pas de point), +- Votre module est votre point d'entrée (vous l'avez exécuté spécifiquement), donc son nom devient `__main__` et ne fait donc pas partie d'un package + +---- + +On peut aussi importer un module qui se trouve dans un répertoire parent. En partant de `submodule_1a`, on peut écrire (notez les deux points) : + +```python +from ..module_b import function1 +from ...module_top import functiona +``` + +Plus je souhaite remonter dans l'arborescence, plus je peux ajouter de points à mon import (même si c'est déconseillé). + +---- + +## Les imports circulaires + +Lorsque l'on écrit des projets complexes, il peut arriver au bout d'un moment que notre code finisse par effectuer les actions +suivantes : + +. . . + +- `module1` importe depuis `module2`, +- `module2` importe depuis `module3`, +- `module3` importe depuis `module1`. + + +. . . + +Ici, `module1` importe indirectement `module3` et `module3` importe `module1`. Ceci est un import circulaire. + +---- + +Dans un tel cas de figure, l'import est impossible car l'import depuis `module3` nécessite que `module1` ait fini d'être chargé... or `module1` ne peut se charger que si `module2` et indirectement `module3` ont été chargés. + +Lorsque cela se produit, votre structure doit être modifiée, soit en déplaçant une partie du code qui serait écrite +dans `module1` et utilisée par `module3`, soit en déplaçant une partie de `module2` et `module3` dans `module1` (moins recommandable). + +---- + +## J'écris quoi, package ou module ? + +Vous pouvez vous demander, puisqu'au niveau de l'interpréteur, package ou module ne font aucune différence, si +dans certains cas, c'est raisonnable de créer un package à la place d'un module. + +La règle générale peut se découper ainsi pour savoir si vous devriez utiliser un package : + +- Le nom du module donne une indication sur le périmètre de son code, +- Si ce périmètre vous semble large (notamment en fonctionnalités et lignes de code), +- Si vous pensez que ce périmètre peut être découpé en sous-catégories, +- Alors vous devriez probablement utiliser un package. (et un module sinon) + +---- diff --git a/documentation/99-more-language.md b/documentation/99-more-language.md new file mode 100644 index 0000000..95e82c7 --- /dev/null +++ b/documentation/99-more-language.md @@ -0,0 +1,47 @@ +--- +title: Plus de langage +author: Steve Kossouho +--- + +# Je sais tout, je vais à la FAQ + +---- + +## Le langage Python + +---- + +### J'ai deux listes de même taille, comment les grouper en dictionnaire ? + +Si vous avez deux listes, et que vous souhaitez en former un dictionnaire tel que `d1`, comme suit : + +```{.python .numberLines} +l1 = ["free", "developer", "enterprise"] +l2 = ["0€", "9.99€", "12.99€"] +d1 = {"free": "0€", "developer": "9.99€", "enterprise": "12.99€"} +``` + +Vous pouvez utiliser la fonction `zip` de Python, de la façon suivante : + +---- + +```{.python .numberLines} +l1 = ["free", "developer", "enterprise"] +l2 = ["0€", "9.99€", "12.99€"] +join = zip(l1, l2) # renvoie une liste contenant [l1[0], l2[0]], puis [l1[1], l2[1]], etc. +d1 = dict(join) +``` + +---- + +### Énumérer les éléments d'une séquence + +Si j'ai une séquence : + + +```{.python .numberLines} +seq = [25, 40, 55, 19] +for idx, number in enumerate(seq): + print(f"Itération {idx} : {number}.") +``` + diff --git a/documentation/99-more-packages.md b/documentation/99-more-packages.md new file mode 100644 index 0000000..4f2af01 --- /dev/null +++ b/documentation/99-more-packages.md @@ -0,0 +1,208 @@ +--- +title: Les paquets externes +author: Steve Kossouho +mainfont: Source Sans Pro +--- + +# Plus de paquets + +---- + +L'écosystème de paquets tiers pour Python est regroupé essentiellement sur un dépôt officiel, nommé [PyPI](https://pypi.org) (Python Package Index). + +Outre l'utilisation de `pip` pour y accéder, quelques questions sont occasionnellement posées quant à la perennité de ces paquets dans des environnements professionnels, notamment où la sécurité importe particulièrement. + +---- + +## Critères d'un paquet de qualité + +Plusieurs critères font d'une bibliothèque un atout de choix dans une pile technique (limitent le risque); + +- Pris en charge par une société établie (l'argent appelle l'argent), +- Existe depuis longtemps (2 ans), et est mis à jour régulièrement avec une gestion active des tickets, +- Est correctement et régulièrement documenté, +- La communauté connaît et utilise suffisamment cette bibliothèque, + +---- + +Ce n'est pas tout : + +- Des sociétés privées proposent une prise en charge technique de la bibliothèque, +- Des sociétés établies s'en servent en production ! (bon, une des pires failles de l'histoire avec log4j en 2021 était potentiellement exploitable chez toutes les Fortune500) + +---- + +## Rappel sur l'utilisation de `pip` + +`pip` est un programme installé avec Python qui vous permet de télécharger et installer (dans votre virtualenv ou autre) des +paquets du dépôt PyPI. On peut l'utiliser de plein de façons différentes, mais l'essentiel, c'est d'ouvrir un terminal et de +taper (évidemment il faut remplacer les éléments nécessaires) + +```shell +pip install +``` + +---- + +## Traitement du texte + +- `unidecode` : retirer les accents et translittérer. +- `nltk` : usine à gaz pour le traitement du langage naturel (500+ Mo) +- `chardet` : bibliothèque capable de suggérer une page de code pour un fichier texte (devine s'il s'agit de UTF8, UTF16, 850, 1252, etc.) + +---- + +## Dates et heures + +- `pytz` : simplifier le cauchemar des fuseaux horaires dans la bibliothèque standard. (corrigé dans Python 3.9 avec `zoneinfo`) +- `pendulum` : traitement des dates, intervalles et dé/encodage de texte. +- `arrow` : traitement des dates etc. +- `ciso8601` : décodage rapide de chaînes de dates. Suivi en vitesse par `pendulum`. + +---- + +## Web + +- `flask` : microframework pour faire du web. Démarrage rapide, évolution plus compliquée. +- `django` : framework web efficace et complet avec son propre ORM. +- `fastapi` : framework pour écrire des API REST, récent. +- `jupyter` : console Python interactive avancée +- `jupyterlab` : console Python interactive avancée (encore plus avancée) + +---- + +## Réseau + +- `scapy` : manipulation de paquets réseau +- `paramiko` : implémentation du protocole SSHv2 + +---- + +## ORM + +- `sqlalchemy` : l'ORM de prédilection utilisé avec Flask +- `peewee` : ORM inspiré de Django +- `ponyorm` : ORM bien pensé + +---- + +## Automatisation + +- `fabric` : exécution de scripts sur plusieurs machines distantes via SSH. +- `ansible` : très utilisé pour exécuter des trucs sur des machines via SSH. +- `celery` : une file de tâches en Python, utilisable comme un cron, avec monitoring. +- `selenium` : automatisation d'actions dans un navigateur web pour tests ou autres. +- `playwright` : automatisation de navigateur web, meilleure expérience que Selenium. Par Microsoft. +- `mouse` : émuler et/ou réagir à des actions souris. +- `keyboard` : émuler et/ou réagir à des actions clavier. +- `faker` : générer des données factices (noms, adresses, clés d'API, nationalité, lorem etc.) + +---- + +## Fichiers structurés + +- `pandas` : Analyse de données tabulaires : Excel, JSON, CSV... tri, calcul, et génération de graphiques. +- `dask` : Analyse de données parallélisable. +- `modin` : Pandas parallélisable avec plusieurs backends disponibles. +- `pyspark` : Analyse de données clusterisable (avec Spark). +- `optimus` : boîte à outils d'analyse de données, peut utiliser `pandas`. +- `spire.xls` : manipulation de fichiers Excel et export dans plusieurs formats dont PDF. [Lien](https://pypi.org/project/Spire.Xls/) +- `pdfkit` : générer du PDF depuis du HTML +- `weasyprint` : générer des documents PDFbdepuis du HTML. Full Python, plus stable. +- `reportlab` : usine à gaz pour créer du PDF. +- `pypdf2` : manipuler des PDF (rotation, découpage des pages etc.) + +---- + +- `lxml` : manipuler des XML +- `beautifulsoup4` : manipuler du code HTML + +---- + +## Manipuler des images + +- `pillow` : bibliothèque classique pour créer et traiter des images. +- `pyside` : possède une classe QImage performante. +- `skia` : par Google, dessin vectoriel, depuis env. 2017. +- `cairo` : dessin vectoriel, depuis env. 2005. +- `wand` : utiliser les fonctionnalités de ImageMagick. +- `ffmpeg-python` : utiliser les fonctionnalités de FFMPeg + +---- + +## HTTP + +- `requests` : facilite le HTTP. Capable de désérialiser du JSON depuis une réponse HTTP. +- `python-dotenv` : permet de charger des informations depuis un fichier d'environnement (.env) +- `fastapi` : concevez rapidement une API REST en Python. + +---- + +## IA et vision assistée par ordinateur + +- `keras` : IA plus facile en Python. Dépend de TensorFlow. +- `tensorflow` : IA en Python. +- `pytorch` : IA en Python. +- `opencv` : incontournable pour le traitement d'images et la détection de caractéristiques. + +---- + +## Calcul + +- `numpy` : calcul rapide sur des données matricielles, tabulaires ou en n-dimensions. +- `scikit-learn` : apprentissage machine. + +---- + +## Afficher des graphiques + +- `matplotlib` : bibliothèque d'affichage de graphes +- `pygal` : bibliothèque d'affichage de graphes en SVG +- `seaborn` : plus élégant que Matplotlib pour afficher des graphiques +- `plotly` : affichage de graphiques via les technologies web +- `dash` : générer des tableaux de bord avec des graphiques (entre autres) + +---- + +## Formatage du code Python et vérification stylistique + +- `black` : formate votre code sans poser de question. Très utilisé professionnellement. +- `pylint` : indique tous les problèmes de normes et convention dans votre code. +- `flake8` : problèmes de normes et convention, plutôt orienté PEP8. +- `isort` : trie les imports automatiquement. +- `radon` : outil de génération de métriques sur le code. +- `mypy` : vérification des annotations de type. + +---- + +## Boilerplate Python + +- `attrs` : Bibliothèque de décorateurs pour `dataclasses` + +---- + +## Spécialité Windows + +- `winregistry` : accès simplifié à la base de registre Windows. + +---- + +## Générer des exécutables + +- `pyinstaller` : Convertisseur de scripts Python en exécutables autonomes. +- `py2exe` : Idem. + +[Comparaison avec d'autres packagers](https://pyoxidizer.readthedocs.io/en/stable/pyoxidizer_comparisons.html) + +---- + +## Awesome Python + +[Curation des meilleurs paquets Python](https://github.com/vinta/awesome-python) + + +---- + +Ressources d'entraînement à Python + +https://store.steampowered.com/app/1067220/RoboCo/ diff --git a/documentation/99-more-virtualenv.md b/documentation/99-more-virtualenv.md new file mode 100644 index 0000000..25af895 --- /dev/null +++ b/documentation/99-more-virtualenv.md @@ -0,0 +1,283 @@ +--- +title: Exporter un environnement Python +author: Steve Kossouho +mainfont: Source Sans Pro +--- + +# Exporter un environnement virtuel entre deux machines + +Ou comment recréer un environnement virtuel sans devoir réinstaller toutes les dépendances à la main… + +---- + +## Exporter l'environnement virtuel + +Les environnements virtuels sont contenus dans des dossiers, et sont généralement dépendants du système sur lequel ils sont créés : + +- L'exécutable `bin/python` y est un lien symbolique vers l'interpréteur Python qui a servi à créer l'environnement (version, OS, architecture processeur) +- les paquets externes écrits en C, et qui sont donc compilés, ne sont utilisables que sur une configuration spécifique (par exemple. Linux sur x86/64 Python 3.11, ou Windows sur ARM64 Python 3.12, ou Linux x86/32 Python 3.9 etc.); une release d'un tel paquet va générer de nombreuses variantes, et une seule version de Numpy existe actuellement dans 44 variantes. + +Il serait rare qu'une simple copie du répertoire d'environnement virtuel permette de le réutiliser ailleurs. + +---- + +…Et d'ailleurs, il existe une bien meilleure idée, beaucoup plus économe en efforts : + +`pip` propose justement un moyen d'échanger une liste des dépendances installées dans l'environnement virtuel, pour pouvoir très simplement les réinstaller sur un autre système. Cette liste est appelée `fichier de dépendances`, ou `requirements.txt`. Elle est très souvent fournie avec des projets Python, justement pour en simplifier le partage et la réutilisation. + +---- + +```{.bash .numberLines} +pip freeze --local > requirements.txt +``` + +Dans le terminal de votre projet (si votre environnement virtuel est activé, ce qui est le cas dans PyCharm), cette commande génère un fichier texte, `requirements.txt` qui contiendra une liste des paquets installés dans votre environnement ainsi que leur version. + +---- + +Sur votre système cible, vous pouvez ensuite réimporter ce fichier et installer toutes les dépendances qui y sont inscrites avec cette commande : + +```{.bash .numberLines} +pip install -r requirements.txt +``` + +Elles seront installées dans l'environnement virtuel actuellement activé. (pensez bien à l'y créer et à l'activer si besoin !) + +---- + +## Créer manuellement un environnement virtuel + +Pour créer un environnement virtuel Python, dans un terminal, tapez : + +```{.bash .numberLines} +python -m venv +``` + +Le dossier créé contiendra un répertoire `bin` (`scripts` sous Windows) et un répertoire `lib`. + +---- + +## Comment activer/désactiver un environnement virtuel + +Vos environnements virtuels possèdent un sous-répertoire `bin`. +Pour activer et utiliser automatiquement votre environnement virtuel, il faut se rendre dans le dossier `bin` et taper dans un terminal : + +```{.bash .numberLines} +source ./activate # ou activate.csh ou activate.fish +``` + +Sous Windows, vous devez plutôt simplement exécuter une commande : + +```bash {.numberLines} +./scripts/activate.ps1 # Dans le powershell si vous êtes dans le répertoire du venv +``` + +(ça peut être `activate.fish` si votre shell utilise fish, et ainsi de suite...) +Votre invite de commande devrait contenir un nouvel élément, au moins entre parenthèses, vous indiquant que l'environnement virtuel est bien activé et utilisé. + +---- + +Pour ensuite désactiver cet environnement virtuel, il vous suffit, dans le terminal où l'environnement est activé, de saisir : + +```{.bash .numberLines} +deactivate +``` + +L'invite de commande du shell ne contiendra plus l'ajout indiquant que votre environnement est actuellement utilisé. +(Quand PyCharm active automatiquement un venv, la commande `deactivate`{.bash} est indisponible) + +---- + +## Comment uniquement télécharger des paquets externes pour les machines déconnectées ? + +Effectivement, vous pourriez vouloir créer un environnement où des machines nécessitant des paquets Python n'ont +pas accès à internet. Dans ce cas, il est possible d'utiliser `pip` pour utiliser un répertoire comme dépôt en remplacement de +PyPI. Ce répertoire peut être un répertoire réseau, par exemple, si vous avez au moins accès au réseau local. + +---- + +Dans l'ordre, pour appliquer une telle mesure, vous pouvez : + +- Utiliser le fichier de dépendances pour télécharger les archives des paquets nécessaires +- Placer les archives dans un dossier accessible sur le réseau (ou localement) +- Utiliser pip sur la machine cible, en précisant de ne pas utiliser PyPI mais notre dossier + +---- + +```{.bash .numberLines} +pip download -r requirements.txt +``` + +Attention, ça va tout télécharger dans le répertoire en cours ! + +---- + +Sur la machine cible, il ne vous reste plus qu'à utiliser `pip` et lui dire d'aller chercher les paquets depuis le répertoire +local ou réseau : + +```{.bash .numberLines} +pip install -r requirements.txt --no-index --find-links=file://chemin/repertoire +``` + +---- + +Si vous souhaitez créer un dépôt compatible avec PyPI, il vous suffit de créer un projet Python et d'installer dans votre environnement virtuel le paquet `pypiserver`. Il est très simple à utiliser, et [cet article chez Linode sur les dépôts pour pip](https://www.linode.com/docs/guides/how-to-create-a-private-python-package-repository/) devrait vous aider à y voir plus clair. + +---- + +## Bonus : PyCharm et la gestion de vos dépendances + +PyCharm est capable de remplir automatiquement votre fichier `requirements.txt` (possiblement avec la version) en analysant le +code de votre projet. + +![Remplissage automatique des dépendances](assets/images/x-requirements-auto-pycharm.jpg) + +---- + +Dans le menu `Tools` → `Sync python requirements` (vous pouvez aussi utiliser le raccourci `Shift + Shift` pour rechercher rapidement l'entrée de menu), PyCharm vous offre un raccourci pour mettre à jour votre fichier de dépendances, conformément aux imports que vous avez utilisés dans votre code. + +Il vous faudra préciser le chemin du fichier `requirements.txt` à mettre à jour, puis configurer la façon dont vous voudrez que PyCharm remplisse les dépendances (intégrer le numéro de version, supprimer les dépendances non utilisées, etc.) + +---- + +## Extra : Gérer des paquets selon l'environnement + +Selon la topologie dans laquelle vous évoluez (contraintes de sécurité incluses, ex. VPN), vous pouvez être amené à organiser vos projets de plusieurs manières. Du plus simple au plus difficile : + +1. Projets Python sur un _dépôt Git public_ +2. Projets Python sur un _dépôt Git privé_ (SSH etc.) +3. Projets Python packagés dans un dépôt brut sur un _répertoire réseau monté_ +4. Projets Python packagés dans un serveur `pip`. + +---- + +### Dépendances + +Lorsque votre projet nécessite d'utiliser des bibliothèques Python pour fonctionner, il est rappelé qu'il est une bonne pratique de fournir avec celui-ci un fichier de _dépendances_. Ce fichier s'appelle par convention `requirements.txt`. Il contient la référence de toutes les bibliothèques que vous utilisez, dans la version dont vous avez besoin. + +```{.requirements.txt .numberLines} +# Exemples de bibliothèques +ipython==8.15.0 # console Python avancée +pyside6==6.5.2 # Qt Framework +``` + +Une fois ce genre de fichier décrit, il est possible d'installer les dépendances qu'il référence avec la commande `pip install -r requirements.txt`. + +---- + +### Dépôt Git public + +Le fichier de dépendances de votre projet, **si vous avez accès à celles-ci**, peut contenir des entrées vers des branches ou des commits de projets présents sur un dépôt Git. Par exemple, si vous souhaitez inclure `Django==3.2.0`, vous pouvez rédiger une entrée similaire au contenu suivant : + +```requirements.txt +# L'entrée est utilisée comme option d'un pip install +git+https://github.com/django/django.git@3.2 +``` + +---- + +### Dépôt Git privé + +Si votre entrée provient d'une usine logicielle et que votre dépôt est privé, l'entrée de votre fichier de dépendances reste la même, mais vous devrez peut-être posséder des identifiants pour y accéder. En général, autoriser une clé SSH configurée sur votre machine de développement sera nécessaire, mais probablement la seule étape nécessaire. + +---- + +### Dossier monté + +Monter un dossier distant consiste à rendre disponible localement l'accès à un répertoire présent sur une machine à distance (généralement un NAS). + +Il est possible de demander à l'outil `pip` de télécharger et d'installer des paquets disponibles sur le protocole `file://`, à condition d'utiliser l'option `pip install -r requirements.txt --find-links=file:///path/to/dir`. + +Les paquets proposés par vos collègues doivent être installables par `pip` et les archives (aux formats `.tar.gz` et `.whl`) doivent être disponibles dans ce répertoire. [Voir le protocole officiel pour la création de paquets Python](https://packaging.python.org/en/latest/tutorials/packaging-projects/) + +---- + +### Imports dynamiques + +Il peut arriver que, lors de la création d'une bibliothèque, un développeur doive s'adapter à des situations où certains imports ne seront pas disponibles. +Un cas extrême serait d'introduire l'utilisation de `pathlib` (disponible uniquement dans Python 3.4+), alors que votre bibliothèque est censée pouvoir fonctionner dans un environnement Python 2.7. + +Techniquement, c'est une mauvaise idée de s'y prendre ainsi, mais si le choix n'est pas permis, il faut passer par certaines stratégies. + +---- + +#### Imports alternatifs + +La façon la plus connue de venir à bout de la possibilité d'utiliser des imports différents selon l'environnement consiste à utiliser la gestion d'exceptions : + +```python {.numberLines} +try: + import package1 + print("Package1 importé !") +except ImportError: + print("Erreur lors de l'importation de package1.") + try: + import package2 + print("Package2 importé !") + except ImportError: + print("Erreur lors de l'importation de package2.") + exit() +``` + +---- + +Une autre façon plus contrôlée, mais plus rarement vue en production, consiste à interroger la version de l'interpréteur pour choisir quel package ou module importer : + +```python {.numberLines} +# Récupère un objet représentant l'interpréteur Python +from sys import version_info + +if version_info.major == 3: + import pathlib + filename = pathlib.Path("/home/demo/readme.txt").parent +else: + from os import path + filename = path.dirname("/home/demo/readme.txt") +``` + +---- + +#### Imports dynamiques par nom + +Vous pouvez, en Python, importer un module ou un package par son nom complet. La méthode fonctionne aussi bien dans Python 2 que Python 3 . + +Elle est un peu compliquée à utiliser, et accepte plusieurs arguments : + + +```{.python .numberLines} +path = __import__("os.path", globals(), locals(), ["basename", "join"], 0) +basename = path.basename +join = path.join +``` + +---- + +#### Imports depuis des répertoires personnalisés + +Lorsque vous avez des modules dans des répertoires personnalisés, vous pouvez ajouter lesdits répertoires au `PYTHONPATH` : + +```{.python .numberLines} +import sys + +# Ajouter le répertoire au PYTHONPATH +sys.path.append("/home/new_path/root") +import mon_module # dans le répertoire +``` + +---- + +### Configurations + +Lire des informations sous la forme de fichiers .ini : + +```{.python .numberLines} +import configparser + +data = configparser.ConfigParser().read("/home/demo/file.ini") +``` + +---- + +### Variables d'environnement + +Une technique utilisée dans certains projets pour configurer certaines options (mots de passe, clés d'API) consiste à créer un fichier de configuration, que certaines bibliothèques peuvent charger et appliquer aux variables d'environnement (variables stockées par le système d'exploitation, différentes de la base de registre Windows) diff --git a/documentation/99-useful-functions.md b/documentation/99-useful-functions.md new file mode 100644 index 0000000..7de91ec --- /dev/null +++ b/documentation/99-useful-functions.md @@ -0,0 +1,289 @@ +# Fonctions utiles en Python + +---- + +## Fonctions de types de données + +---- + +### `int` + +La fonction `int()` convertit une valeur en un entier. Si aucun argument n'est fourni, elle retourne 0. + +```{.python .numberLines} +x = int(2.8) # x sera 2 +y = int("3") # y sera 3 +z = int() # z sera 0 +w = int("6f", base=16) # w sera 111 +v = int("10101", base=2) # v sera 21 +``` + +---- + +### `str` + +La fonction `str()` convertit une valeur en une chaîne. Si aucun argument n'est fourni, elle retourne une chaîne vide. + +```{.python .numberLines} +x = str(2) # x sera "2" +y = str(3.8) # y sera "3.8" +z = str() # z sera "" +``` + +---- + +### `float` + +La fonction `float()` convertit une valeur en un nombre à virgule flottante. Si aucun argument n'est fourni, elle retourne 0.0. + +```{.python .numberLines} +x = float(2) # x sera 2.0 +y = float("3.8") # y sera 3.8 +z = float() # z sera 0.0 +``` + +---- + +### `list` + +La fonction `list()` est utilisée pour créer une liste. + +```{.python .numberLines} +x = list((1, 2, 3)) # x sera [1, 2, 3] +y = list("oui") # y sera ["o", "u", "i"] +z = list() # z sera une nouvelle liste vide +``` + +---- + +### `dict` + +La fonction `dict()` est utilisée pour créer un dictionnaire. + +```{.python .numberLines} +x = dict(name="John", age=36) # x sera {'name': 'John', 'age': 36} +y = dict([("name", "John"), ("age", 36)]) # y sera {'name': 'John', 'age': 36} +z = dict() # z sera un nouveau dictionnaire vide +``` + +---- + +## Fonctions d'introspection + +---- + +### `locals` + +La fonction `locals()` renvoie un dictionnaire contenant les variables locales courantes. + +```{.python .numberLines} +def ma_fonction(): + x = 2 + print(locals()) # Dictionnaire des variables disponibles au niveau de la fonction + +ma_fonction() # Affiche {'x': 2} +``` + +---- + +### `getattr` + +La fonction `getattr()` renvoie la valeur de l'attribut nommé d'un objet. + +```{.python .numberLines} +class MaClasse: + x = 2 + +objet = MaClasse() +print(getattr(objet, "x")) # Affiche 2 +print(getattr(objet, "y")) # Provoque une erreur +print(getattr(objet, "y", None)) # Affiche None si y est introuvable comme attribut de objet +``` + +---- + +### `type` + +La fonction `type()` renvoie le type d'un objet. + +```{.python .numberLines} +x = 2 +print(type(x)) # Affiche +``` + +---- + +### `isinstance` + +La fonction `isinstance()` vérifie si un objet est une instance d'une classe spécifique. + +```{.python .numberLines} +class MaClasse: + pass + +objet = MaClasse() +print(isinstance(objet, MaClasse)) # Affiche True +``` + +---- + +### `dir` + +La fonction `dir()` tente de renvoyer une liste d'attributs valides de l'objet. + +```{.python .numberLines} +print(dir("Hello")) # Affiche une liste de méthodes et attributs de la classe str +``` + +---- + +## Fonctions utiles + +---- + +### `print` + +La fonction `print()` affiche les arguments à l'écran. + +```{.python .numberLines} +print("Bonjour, monde !") # Affiche Bonjour, monde ! +print("Je voudrais", 2, "baguettes.") +``` + +---- + +### `all` + +La fonction `all()` renvoie `True` si **tous** les éléments d'un itérable sont vrais (ou équivalents, à savoir non +nuls ou non vides). + +```{.python .numberLines} +liste = [True, True, True] +print(all(liste)) # Affiche True +``` + +---- + +### `any` + +La fonction `any()` renvoie `True` si au moins un élément d'un itérable est vrai. + +```{.python .numberLines} +liste = [False, True, False] +print(any(liste)) # Affiche True +``` + +---- + +### `ord` + +La fonction `ord()` renvoie un entier représentant le code Unicode du caractère fourni. + +```{.python .numberLines} +print(ord('A')) # Affiche 65 +print(ord('a')) # Affiche 97 +``` + +---- + +### `max` + +La fonction `max()` renvoie le plus grand élément d'un itérable ou le plus grand de deux ou plusieurs arguments. + +```{.python .numberLines} +print(max(1, 2, 3)) # Affiche 3 +``` + +---- + +### `min` + +La fonction `min()` renvoie le plus petit élément d'un itérable ou le plus petit de deux ou plusieurs arguments. + +```{.python .numberLines} +print(min(1, 2, 3)) # Affiche 1 +``` + +---- + +### `input` + +La fonction `input()` lit une ligne à partir de l'entrée de la console, et renvoie le texte saisi, toujours sous forme +de chaîne de caractères. + +```{.python .numberLines} +nom = input("Entrez votre nom : ") +print(nom) +``` + +---- + +### `round` + +La fonction `round()` arrondit un nombre à un certain nombre de décimales. + +```{.python .numberLines} +print(round(3.14159, 2)) # Affiche 3.14 +``` + +---- + +### `enumerate` + +La fonction `enumerate()` permet à chaque itération sur un objet, de renvoyer un tuple de taille 2, +contenant toujours un numéro séquentiel, suivi de l'élément parcouru à l'itération en cours. + +```{.python .numberLines} +for i, v in enumerate(['a', 'b', 'c']): + print(i, v) +``` + +Affiche `0 a`, `1 b` puis `2 c`. + +---- + +### `len` + +La fonction `len()` renvoie le nombre d'éléments dans un objet. + +```{.python .numberLines} +print(len("Bonjour")) # Affiche 7 +``` + +---- + +### `range` + +La fonction `range()` génère une séquence de nombres. La valeur de fin n'est jamais incluse dans l'intervalle. + +```{.python .numberLines} +for i in range(5): + print(i) # Affiche les nombres de 0 à 4 +``` + +```{.python .numberLines} +for i in range(5, 15): + print(i) # Affiche les nombres de 5 à 14 +``` + +```{.python .numberLines} +for i in range(5, 15, 3): + print(i) # Affiche les nombres 5, 8, 11 et 14 +``` + +---- + +### `zip` + +La fonction `zip()` combine les éléments de + + plusieurs itérables en tuples. + +```{.python .numberLines} +nombres = [1, 2, 3] +lettres = ['a', 'b', 'c'] +for n, l in zip(nombres, lettres): + print(n, l) +``` + +---- diff --git a/documentation/99-windows-install.md b/documentation/99-windows-install.md new file mode 100644 index 0000000..ca166d9 --- /dev/null +++ b/documentation/99-windows-install.md @@ -0,0 +1,35 @@ +--- +title: Installer Python et PyCharm +author: Steve Kossouho +--- + +# Installer PyCharm et Python sous Windows + +---- + +## Installer Python + +Pour pouvoir exécuter vos scripts Python, vous devez naturellement installer Python (l'interpréteur et les outils associés). +Le [site officiel de Python](https://www.python.org/) propose des téléchargements pour plusieurs plateformes, mais seul Windows nécessite +d'effectuer une installation via un téléchargement. + +---- + +### Étapes + +1. Se rendre sur [Téléchargements Python](https://www.python.org/downloads/windows/); +2. Dans la section `Stable Releases` (à gauche), cliquer `Download Windows installer (64-bit)` pour la dernière version; +3. Après le téléchargement, exécuter le fichier; **Attention** : +4. Pendant l'exécution de l'installateur, **cochez** à tout prix l'option mentionnant un `PATH` +5. Après l'installation, vous pouvez vérifier que tout va bien en lançant l'application Windows `Powershell` et en y tapant `python`; +6. Si tout va bien, la console Python devrait se lancer. Si vous avez manqué une étape, Windows Store devrait s'ouvrir ou un message d'erreur devrait apparaître. + +---- + +## Installer PyCharm + +Le logiciel PyCharm est très facile à installer, et nécessite seulement de se rendre sur le site de JetBrains : + +1. Rendez-vous sur [Téléchargement PyCharm pour Windows](https://www.jetbrains.com/fr-fr/pycharm/download/?section=windows); +2. Pour directement télécharger la version gratuite (plus bas dans la page), suivez ce lien : [Téléchargement PyCharm Community](https://www.jetbrains.com/fr-fr/pycharm/download/download-thanks.html?platform=windows&code=PCC) +3. L'installation devrait être simple à effectuer. diff --git a/documentation/99-windows-restrained-install-general.md b/documentation/99-windows-restrained-install-general.md new file mode 100644 index 0000000..69236a0 --- /dev/null +++ b/documentation/99-windows-restrained-install-general.md @@ -0,0 +1,94 @@ +--- +title: Python et PyCharm avec une brique et un trombone +author: Steve Kossouho +--- + +# Installer PyCharm et Python sous Windows + +Dans un environnement contraint : + +- Pas de droits administrateur sur la machine +- Pas d'accès à la majorité des noms de domaine + +---- + +## Installer Python + +Lorsqu'il est impossible d'**installer** Python sur une machine, il est généralement possible d'en exécuter tout de +même une version dite portable. Il existe deux packages portables, le package officiel du site Python (incomplet pour nos besoins), +ainsi qu'une version nommée **WinPython** : + +- [WinPython 3.12 Windows 64-bit](https://github.com/winpython/winpython/releases/download/7.5.20240410final/Winpython64-3.12.3.0dot.exe) (19 avril 2024) +- [Python 3.12.4 Windows 64-bit embeddable](https://www.python.org/ftp/python/3.12.4/python-3.12.4-embed-amd64.zip) (6 juin 2024) + +Un seul des deux liens est nécessaire, **préférez WinPython** car il contient des outils supplémentaires pour Python, notamment +la bibliothèque interne pour créer des environnements virtuels. + +---- + +## Installer PyCharm + +Le logiciel PyCharm semble s'installer même sans les droits administrateur, et nécessite seulement de se rendre sur le site de JetBrains : + +1. Rendez-vous en bas de [Téléchargement PyCharm pour Windows](https://www.jetbrains.com/fr-fr/pycharm/download/?section=windows); +2. Pour directement télécharger la version gratuite (**plus bas dans la page**), suivez ce lien : [Téléchargement PyCharm Community](https://www.jetbrains.com/fr-fr/pycharm/download/download-thanks.html?platform=windows&code=PCC) +3. L'installation devrait se lancer malgré l'invite d'accès administrateur. + +---- + +### Gérer ses environnements virtuels et projets + +Nous avons vu comment créer des venv pour Python. Dans votre configuration, il est conseillé de se baser sur l'interface de PyCharm +pour les créer, en observant quelques précautions : + +- Le dossier pour créer le venv devrait être un dossier vide +- Le nom de ce dossier peut débuter par un `.` pour le différencier des autres dossiers de projet +- Pour le reconnaître _a posteriori_, préférez le nommer avec le terme `venv` +- Préférez également ne pas le nommer avec des majuscules, des tirets ou des espaces + +---- + +## Utiliser l'outil pip + +---- + +### Installer des paquets depuis un répertoire local + +Si vous souhaitez installer des paquets qui sont (avec leurs dépendances) disponibles dans un répertoire local avec `pip`, que ce +soit via un fichier `requirements.txt` ou manuellement, vous devez utiliser l'une des commandes suivantes (les options sont les plus importantes) : + +```bash {.numberLines} +pip install -r requirements.txt --no-index --find-links= +``` + +```bash {.numberLines} +pip install --no-index --find-links= +``` + +- L'option `--no-index` désactive la recherche de paquets sur le PyPI +- L'option `--find-links` permet d'indiquer où chercher des paquets + +---- + +### Configurer pip pour utiliser automatiquement un dépôt personnalisé + +Il est possible de créer un fichier de configuration que pip trouve automatiquement pour utiliser par défaut +certaines options. + +- Sous Linux : `/home//.pip/pip.conf` ou [Dans le répertoire du venv](https://pip.pypa.io/en/stable/topics/configuration/#location) +- Sous Windows : [Dans le répertoire du venv](https://pip.pypa.io/en/stable/topics/configuration/#location) + +---- + +### Contenu du fichier de configuration (Exemple) + +Le fichier que vous devez créer est différent selon le système d'exploitation (voir slide précédent), mais son contenu +est toujours le même si vous êtes dans le même réseau d'entreprise : + +```ini {.numberLines} +[global] +index = https://... +index-url = https://... +trusted-host = ... +``` + diff --git a/documentation/assets/books/apprendre-python-3-gerard-swinnen-2012.pdf b/documentation/assets/books/apprendre-python-3-gerard-swinnen-2012.pdf new file mode 100644 index 0000000..cd903f8 Binary files /dev/null and b/documentation/assets/books/apprendre-python-3-gerard-swinnen-2012.pdf differ diff --git a/documentation/assets/diagrams/class-simple-dog.gaphor b/documentation/assets/diagrams/class-simple-dog.gaphor new file mode 100644 index 0000000..6113440 --- /dev/null +++ b/documentation/assets/diagrams/class-simple-dog.gaphor @@ -0,0 +1,335 @@ + + + + + +New model + + + + + + + + + + + + + + + + + + + +main + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 612.0, 100.0) + + +172.0 + + +159.0 + + + + + + + + + + +Dog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +name + + + + + + + +age + + + + + + + +eat + + + + + + + + + + + + +bark + + + + + + + + + + + + +wag_tail + + + + + + + + + +speed + + + + + + + +loudness + + + + + + + +quantity + + + + + + + + + + +1 + + +create + + + + +DogOwner + + + + + + + + + + + + + + + + + + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 190.0, 99.0) + + +176.0 + + +159.0 + + + + + + + + + + + + + +name + + + + + + + +age + + + + + + + +address + + + + + + + +walk_dog + + + + + + + +feed_dog + + + + + + + + + + +0 + + +1 + + + + + + + + +(1.0, 0.0, 0.0, 1.0, 264.0, 165.0) + + +[(102.0, 4.784901835968924), (102.0, 37.88461538461539), (348.0, 37.88461538461539)] + + + + + + + + + + + + + + + + +owns + + + + + + + + + + + + + + + + + + +shared + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/assets/diagrams/introduction.drawio b/documentation/assets/diagrams/introduction.drawio new file mode 100644 index 0000000..fe10590 --- /dev/null +++ b/documentation/assets/diagrams/introduction.drawio @@ -0,0 +1 @@ +7VvZcuI4FP0aHpPywpZHIEt3TzpDN5lkXgUWoEG2GFmE0F/fV7a8KoCd4HZCqEpVrGtZtnSOro6OTcMeuM83HC3n35mDacMynOeGfdmwLLNpdOGfjGzCSOfCCAMzThxVKQmMyC+sglG1FXGwn6koGKOCLLPBCfM8PBGZGOKcrbPVpoxm77pEM6wFRhNE9egjccQ8jHatThL/gslsHt3ZbF+EZ1wUVVY98efIYetUyL5q2APOmAiP3OcBpnLwonF5/Lp5pLeL9s23H/7/6J/+X/d3D2dhY9dlLom7wLEnXt30r8X0+stD879/l8PrH2vjpjf+dqYuMZ4QXanxGmLuM0/1WGyiYfTXxKXIg1J/yjwxUmdgEPqIkpkHxxN4Oswh8IS5IIBAT50QbAnRyZxQ5xZt2Er2wRdosohK/Tnj5Bc0iyicMiEAp7lQZLLamRojeSWEDYhy7EOdYTQwZhy6Rb5QdSaMUrT0yTh4YFnFRXxGvD4TgrlRQ2zlOdhRpRjpoCA4W8TckdcXhEPBJkcDP6fIqOC5wczFgm+gijobM01NNTMqrxPimm0Vm6dJa6tJitRkmcVtx7f7CZMLeTMYhOR+du5+zYL3A0Qyt0MUgPeQwH05jH6ahnCQ6moSCshZgqimRtQ75GKNpjDSIkVJiqdiKyH9JZoQb3Yb1LlsJpGfqqcyxODaKQ3IMCeOg72ALAIJFPJJMmTJiCeCoWj14Q8GbGCctxoteKABlM2kDH+yOhcD5gGvEAkIhIGsaywJ+wK1dk7b/dTaZBEri2yaSBlIy+Jn6YlmzjxJxruVO4a0cWxI7sgoc+FSdVgV3i2rZrxtDe8rFxF5Wc9xIEf7J8APCninWzPgTQ1wDWFKAv2gRsN8cW3dA78LQMrmIrzvJR0uz0yNE7bOCfsF/CkaYzpkPhGEyfZ5WDfHi7qytmk0i6G6Y/l/E6gtPWuv+GSOfJm4QXYtYHiDoyOcz5WBatadm9saqiOxcmQ3C6p+46T6D6f6zZzqt9vVqn4zp/rt7vtV/Z3tTD1W3Vgw7bQL0+y97AC6GpY9eHrp3ljGd1hKjg7JgwrC0njXvgO4OAnCg4NaVOVXpQdN3S/8ConfuAI0yBgFy8w9kwGPM9nckU3ptAhqVgVyt+5Mbepm2w2WS+4Iu8RDXCJ+jxZYd4k/Or5VQVq/5o8eYFc6xp7Tk29coDSmTMrtPoSUHjeNsHhNaLR07RHM2fUPOzMcTR1Mx2x9lQT6QQBOREwpLbd9BvtSvB8y2GDMcIHtnHzancC+BCTHFAnylH3xtEOcDyVxE2FuGVlhbhl2tomwk+qq9Juesg2Fo6A1dDCvXjf/hpxNse8zXa+ftpjVbzHt/Jav6BazY+wl8Qs7TLtZYIfZeR87TFP3LUeIIpVxP+HaFk/ej7OzNHWbUkPvs281ysNadANZ2V5Dtyk/lWKJEHvXksXMZfrOKyWLnWvI6uSepWrJojuN295TngRL9YKlFX11VvZLGMvcschsVyyt1gf6EkY3UkeCY6y/vfksiqVTmF7vRrHo5uiAiOPTnAe1wMvjXLsHbul+KSRtcXzfrdUMdO1fv1i6ZQrKXq7iljFgzgnwAwNe+MuY6hDXDdUBjIk4QuegbqztV4qxw2GtG5oayJ/eYCiPa6ugDKvKYbB07+8BIHKOcYGuDsV27ZlYt//+XonlStoLPfmu8lbOgxOihRG9qD3flrP+2DIY63LmXuwLmvVbfWps9zp9EZZ7rT6Fs6RS2tZoqgd6o+sXv8+JCWNlmyjq+rWaexra4vppDZ3l3zjl2mHTqY8rMQ4t3Tg0zs8j4BO6BmZcKhHsSTtjZcmFa3gfTRazgL8DRhmH8x5LDEjldlvFc0I0v9RvLtVjNeLfnxU36s7eyKiImH8MLt08K45VpJ8+KliHmf3RR7l/HDrdM6PQC7nAo63eZ0qO51HVVXARBz/W6LuxLuWiv5EYGgG2caX4OnFxGKbYWRc/StJv4QoUk19ch9WT363bV78B \ No newline at end of file diff --git a/documentation/assets/diagrams/logging-logger-function.drawio b/documentation/assets/diagrams/logging-logger-function.drawio new file mode 100644 index 0000000..7d1013b --- /dev/null +++ b/documentation/assets/diagrams/logging-logger-function.drawio @@ -0,0 +1 @@ +7Vhdb+I4FP01SLsPE+WDQHhsAmwfWmk0aDS7T5WbmMRTJ2ZsQ8n8+rmOHUgw7dIVncxKQ6ViXzv29T33HG48CpJy/xdHm+KeZZiOfDfbj4L5yPe9sRvBl7LU2hKNp9qQc5KZSUfDinzHxuga65ZkWPQmSsaoJJu+MWVVhVPZsyHO2XN/2prR/q4blGPLsEoRta1fSCYLcwp/erTfYpIX7c7eZKZHStRONicRBcrYc8cULEZBwhmTulXuE0xV8Nq46OeWL4weHOO4kpc8sKS7Wy++uQ+eS5Z8+1Z/QpvZB1+vskN0aw68+pwki9XK+CzrNhAZEgVWS7mjIC5kSaHpQZOzbZU1A6onJGdPOGGU8eaxwHWjYDKGkTWrpIHXg7PHiJK8gk4K7mPeTjD7HZdqg+6bGfbS+gCYS7x/MTLeId6QqJiVWPIappgHgqnBrD5kre4/HxGfGlPRAbtFFpkcyw8rH2GAhkHiDahEVvRxBllpuozLguWsQnRxtHZwUAAd59wxtjER/YqlrA0GaCtZH0i9p9ro9TCCX2zLU/yK/4EhKuI5lq/MC8/DwjFFkuz6flw9yIGV+vdYCCUHgGsSjG5cLSsC8hQS9L/xYU0o7aSsN/Xj8fwcTw4jb+KJewlP1s3nGjwJx32eTG2eeP7PJIoX/s+ZEl7IFG88JFW8yRBhhmDy+m/1vBO23X+g+8F1DsPzvVlf9+pu7yPmBM6vSNMYB4BtNiRqoSVwdyzPlZRNKDgdP6pWrlp/gExJrqVPNNo32+kvTqRu/GllgJISAoXSHXrE9CMTRBKmhOqRSclKJUxPWKaFrZAnmgjFFPxZmlixSmVRu8uNkUGpkifeMKLUcLED5IRZ1hJKKLg2ytdyn6va1EmJSNmDQGvsCJxu4Wj1A1EC71CWP5SoggCUTSrE1xDLqC+WfmiL5eSMVkbvpZWHOvSXILHruP5sYBbPLhXfaEgazywa36Iqo1fjcQesf6W0xTGqZsYofcqbTLGrjpcYbFct514d3KWriazfnFSnV3edUpwwMXU0pwWkJalycSU2u26PzcHMZnNwhs3Bu7HZs4D8yWz2opMfZTeMBia0N76U0YP+MLdu/qb0kJQOvV+M0l5kpcUKOEqweQ9lAO8p0khs9K3XmuxVCLtkbYqkxskwHoXzc1iTsrn+sl46jX1OyhyOQskj/EfftxyrI+YY3ocRHGc5x7uHRHvmiF1+HVygGnTCHjIgNa2lWzyFNjah/17Y2L/CB2zWJC3ImRuCYbFZkmuCMp5NTyCxyRJOHLf78Wx82svRN+AD3eMdaTPWuWkOFj8A \ No newline at end of file diff --git a/documentation/assets/diagrams/logging-logger-hierarchy.drawio b/documentation/assets/diagrams/logging-logger-hierarchy.drawio new file mode 100644 index 0000000..980558c --- /dev/null +++ b/documentation/assets/diagrams/logging-logger-hierarchy.drawio @@ -0,0 +1 @@ +7VnJbtswEP0aHxtYu3xsnO2QogUCtEkvBi2OJDaUKNB0LPfrS1qUtTCJncaBHMAncx4XkfPejDT0yJlm5TVHRfqNYaAje4zLkXMxsm3LHYfyRyHrCgkmXgUknGA9qAHuyF/Q4FijS4Jh0RkoGKOCFF0wYnkOkehgiHO26g6LGe0+tUAJGMBdhKiJ/iJYpBUa2kGD3wBJ0vrJlj+pejJUD9YnWaQIs1ULci5HzpQzJqpWVk6BKufVfqnmXb3Qu90Yh1zsM2FZ3FNy/dO7PXd+30+vHlCGH7/oVZ4QXeoD37IkAS4xjiKSg967WNcOkccoVLPgLIKF9O75KiUC7goUKXglZSCxVGRUWpZszlH0mHC2zPH3paBqyQqPCaVTRhnfrOvEcWxHkcQXgrNHaPVgf+57vuzRewUuoHzRCdbWtVKTwDIQfC2H6Am2q9nQcqzNVcOtVROWtnj1NYa0nJLtyo3HZUM7/Q0EeIaDAUsBapNxkbKE5YheNuj5xpmgVh1Lqxlzy1ihnfsHhFjraEJLwbqUQEnEvZp+5mnrQS+m2hdl21jXRi6P25qkzId6PWU00zZWPa86nzrU65RJH7Alj+AVX9k6/hFPQOwStSkBDhQJ8tTdx8EJtY2Ims0yRPLZzGC6y+OOMDqA+MOu9i1vaPGHJ/HvLX7nM4jfMcSPkUCDC7+f9YdXfnBS/t7Kdz+D8q1Bc5nV5nPL7i5G23y26H2B0frDL6ZQflVf1gOxHAxJs2skOFmgDJ7f3PGx5TfLPSW4vaVv1YXtLu07g2Y4s1ZUL/czKCNV8x/ZK94ePgROpd0bQmDf2s4dNATM4k6m/7OISbcwuhg8CPrvgSMIAv+zBMEhxfzePK2n/mBEPrph1++xa/VYq4JHz+oRt93GO7g0qzulfigFH77E844v/weGu25QjunmctU2w4JSUixgt7N696ZgYQ+C5+5NJ37goAPdm/r9u6N9L07DD3Pv5BX3YhipzfhUqAtoifiJamHgOVED+h0cIhnUZgL/X1LiMILnL7Pnoed6448h5QM5kWbzT0WVUJr/e5zLfw== \ No newline at end of file diff --git a/documentation/assets/examples/UML/person.xmi b/documentation/assets/examples/UML/person.xmi new file mode 100644 index 0000000..b936502 --- /dev/null +++ b/documentation/assets/examples/UML/person.xmi @@ -0,0 +1,149 @@ + + + + + umbrello uml modeller 2.32.2 http://umbrello.kde.org + 1.6.19 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/assets/images/basics-sets-hashing.png b/documentation/assets/images/basics-sets-hashing.png new file mode 100644 index 0000000..983c4e3 Binary files /dev/null and b/documentation/assets/images/basics-sets-hashing.png differ diff --git a/documentation/assets/images/basics-sets-operations.jpg b/documentation/assets/images/basics-sets-operations.jpg new file mode 100644 index 0000000..df35b13 Binary files /dev/null and b/documentation/assets/images/basics-sets-operations.jpg differ diff --git a/documentation/assets/images/basics-sets-operations.png b/documentation/assets/images/basics-sets-operations.png new file mode 100644 index 0000000..36b00d4 Binary files /dev/null and b/documentation/assets/images/basics-sets-operations.png differ diff --git a/documentation/assets/images/classes-class-hierarchy.png b/documentation/assets/images/classes-class-hierarchy.png new file mode 100644 index 0000000..56a9c68 Binary files /dev/null and b/documentation/assets/images/classes-class-hierarchy.png differ diff --git a/documentation/assets/images/classes-uml-class.png b/documentation/assets/images/classes-uml-class.png new file mode 100644 index 0000000..f6fff6d Binary files /dev/null and b/documentation/assets/images/classes-uml-class.png differ diff --git a/documentation/assets/images/classes-uml-dog.jpg b/documentation/assets/images/classes-uml-dog.jpg new file mode 100644 index 0000000..a7cc6b0 Binary files /dev/null and b/documentation/assets/images/classes-uml-dog.jpg differ diff --git a/documentation/assets/images/classes-uml-dog.png b/documentation/assets/images/classes-uml-dog.png new file mode 100644 index 0000000..a90f87c Binary files /dev/null and b/documentation/assets/images/classes-uml-dog.png differ diff --git a/documentation/assets/images/database-configure-connection-settings.png b/documentation/assets/images/database-configure-connection-settings.png new file mode 100644 index 0000000..fc15b14 Binary files /dev/null and b/documentation/assets/images/database-configure-connection-settings.png differ diff --git a/documentation/assets/images/database-configure-connection.png b/documentation/assets/images/database-configure-connection.png new file mode 100644 index 0000000..b8a0efa Binary files /dev/null and b/documentation/assets/images/database-configure-connection.png differ diff --git a/documentation/assets/images/database-show-db-browser.png b/documentation/assets/images/database-show-db-browser.png new file mode 100644 index 0000000..afa5814 Binary files /dev/null and b/documentation/assets/images/database-show-db-browser.png differ diff --git a/documentation/assets/images/exception-class-hierarchy.png b/documentation/assets/images/exception-class-hierarchy.png new file mode 100644 index 0000000..015eb64 Binary files /dev/null and b/documentation/assets/images/exception-class-hierarchy.png differ diff --git a/documentation/assets/images/gui-api-pygtk.png b/documentation/assets/images/gui-api-pygtk.png new file mode 100644 index 0000000..97d974b Binary files /dev/null and b/documentation/assets/images/gui-api-pygtk.png differ diff --git a/documentation/assets/images/gui-api-pyside.png b/documentation/assets/images/gui-api-pyside.png new file mode 100644 index 0000000..4947247 Binary files /dev/null and b/documentation/assets/images/gui-api-pyside.png differ diff --git a/documentation/assets/images/gui-api-tkinter.png b/documentation/assets/images/gui-api-tkinter.png new file mode 100644 index 0000000..d4391f5 Binary files /dev/null and b/documentation/assets/images/gui-api-tkinter.png differ diff --git a/documentation/assets/images/gui-api-wxpython.png b/documentation/assets/images/gui-api-wxpython.png new file mode 100644 index 0000000..f11ea68 Binary files /dev/null and b/documentation/assets/images/gui-api-wxpython.png differ diff --git a/documentation/assets/images/gui-base-dialog.png b/documentation/assets/images/gui-base-dialog.png new file mode 100644 index 0000000..d45eba9 Binary files /dev/null and b/documentation/assets/images/gui-base-dialog.png differ diff --git a/documentation/assets/images/gui-designer-loading.png b/documentation/assets/images/gui-designer-loading.png new file mode 100644 index 0000000..98ae30d Binary files /dev/null and b/documentation/assets/images/gui-designer-loading.png differ diff --git a/documentation/assets/images/gui-qtdesigner-layout-1.png b/documentation/assets/images/gui-qtdesigner-layout-1.png new file mode 100644 index 0000000..edccea3 Binary files /dev/null and b/documentation/assets/images/gui-qtdesigner-layout-1.png differ diff --git a/documentation/assets/images/gui-qtdesigner-layout-2.png b/documentation/assets/images/gui-qtdesigner-layout-2.png new file mode 100644 index 0000000..655fc56 Binary files /dev/null and b/documentation/assets/images/gui-qtdesigner-layout-2.png differ diff --git a/documentation/assets/images/gui-qtdesigner-widget-promotion.png b/documentation/assets/images/gui-qtdesigner-widget-promotion.png new file mode 100644 index 0000000..3b194d2 Binary files /dev/null and b/documentation/assets/images/gui-qtdesigner-widget-promotion.png differ diff --git a/documentation/assets/images/gui-qtdesigner.png b/documentation/assets/images/gui-qtdesigner.png new file mode 100644 index 0000000..ea2e5c8 Binary files /dev/null and b/documentation/assets/images/gui-qtdesigner.png differ diff --git a/documentation/assets/images/ide-pycharm.png b/documentation/assets/images/ide-pycharm.png new file mode 100644 index 0000000..9fc4c02 Binary files /dev/null and b/documentation/assets/images/ide-pycharm.png differ diff --git a/documentation/assets/images/intro-guido.jpg b/documentation/assets/images/intro-guido.jpg new file mode 100644 index 0000000..6578c15 Binary files /dev/null and b/documentation/assets/images/intro-guido.jpg differ diff --git a/documentation/assets/images/intro-terminal.png b/documentation/assets/images/intro-terminal.png new file mode 100644 index 0000000..7b28efd Binary files /dev/null and b/documentation/assets/images/intro-terminal.png differ diff --git a/documentation/assets/images/logging-building.png b/documentation/assets/images/logging-building.png new file mode 100644 index 0000000..d330fd8 Binary files /dev/null and b/documentation/assets/images/logging-building.png differ diff --git a/documentation/assets/images/logging-hierarchy.png b/documentation/assets/images/logging-hierarchy.png new file mode 100644 index 0000000..62cc04a Binary files /dev/null and b/documentation/assets/images/logging-hierarchy.png differ diff --git a/documentation/assets/images/x-imports-pycharm-runconfig.png b/documentation/assets/images/x-imports-pycharm-runconfig.png new file mode 100644 index 0000000..c32f0c9 Binary files /dev/null and b/documentation/assets/images/x-imports-pycharm-runconfig.png differ diff --git a/documentation/assets/images/x-imports-pythonpath-pycharm.png b/documentation/assets/images/x-imports-pythonpath-pycharm.png new file mode 100644 index 0000000..d5222ca Binary files /dev/null and b/documentation/assets/images/x-imports-pythonpath-pycharm.png differ diff --git a/documentation/assets/images/x-intro-core-developers-2018.jpg b/documentation/assets/images/x-intro-core-developers-2018.jpg new file mode 100644 index 0000000..776226d Binary files /dev/null and b/documentation/assets/images/x-intro-core-developers-2018.jpg differ diff --git a/documentation/assets/images/x-intro-pycharm.png b/documentation/assets/images/x-intro-pycharm.png new file mode 100644 index 0000000..0dc7cc9 Binary files /dev/null and b/documentation/assets/images/x-intro-pycharm.png differ diff --git a/documentation/assets/images/x-intro-tiobe-2021.jpg b/documentation/assets/images/x-intro-tiobe-2021.jpg new file mode 100644 index 0000000..c10a5e4 Binary files /dev/null and b/documentation/assets/images/x-intro-tiobe-2021.jpg differ diff --git a/documentation/assets/images/x-intro-tiobe-2022.png b/documentation/assets/images/x-intro-tiobe-2022.png new file mode 100644 index 0000000..edc5ede Binary files /dev/null and b/documentation/assets/images/x-intro-tiobe-2022.png differ diff --git a/documentation/assets/images/x-intro-uses-financial.jpg b/documentation/assets/images/x-intro-uses-financial.jpg new file mode 100644 index 0000000..73b2f20 Binary files /dev/null and b/documentation/assets/images/x-intro-uses-financial.jpg differ diff --git a/documentation/assets/images/x-intro-uses-hr.png b/documentation/assets/images/x-intro-uses-hr.png new file mode 100644 index 0000000..4bdea9c Binary files /dev/null and b/documentation/assets/images/x-intro-uses-hr.png differ diff --git a/documentation/assets/images/x-intro-uses-office-work.png b/documentation/assets/images/x-intro-uses-office-work.png new file mode 100644 index 0000000..6f44e3c Binary files /dev/null and b/documentation/assets/images/x-intro-uses-office-work.png differ diff --git a/documentation/assets/images/x-introduction-grammar-error.gif b/documentation/assets/images/x-introduction-grammar-error.gif new file mode 100644 index 0000000..c83f803 Binary files /dev/null and b/documentation/assets/images/x-introduction-grammar-error.gif differ diff --git a/documentation/assets/images/x-outro-end.png b/documentation/assets/images/x-outro-end.png new file mode 100644 index 0000000..b2b09cf Binary files /dev/null and b/documentation/assets/images/x-outro-end.png differ diff --git a/documentation/assets/images/x-requirements-auto-pycharm.jpg b/documentation/assets/images/x-requirements-auto-pycharm.jpg new file mode 100644 index 0000000..8d2d69f Binary files /dev/null and b/documentation/assets/images/x-requirements-auto-pycharm.jpg differ diff --git a/documentation/assets/images/x-venv-gitlab.png b/documentation/assets/images/x-venv-gitlab.png new file mode 100644 index 0000000..f64eace Binary files /dev/null and b/documentation/assets/images/x-venv-gitlab.png differ diff --git a/documentation/assets/images/x-venv-network.png b/documentation/assets/images/x-venv-network.png new file mode 100644 index 0000000..e076c78 Binary files /dev/null and b/documentation/assets/images/x-venv-network.png differ diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..23bd5a2 --- /dev/null +++ b/logo.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/source/02-language-basics/variables-expressions-types/source/base_conversions.py b/source/02-language-basics/variables-expressions-types/source/base_conversions.py new file mode 100644 index 0000000..c4030cc --- /dev/null +++ b/source/02-language-basics/variables-expressions-types/source/base_conversions.py @@ -0,0 +1,40 @@ + +def base_conversions(): + """ + Conversions entre types via les fonctions de base de python. + + """ + # Convertir une chaîne en valeur entière + print(int("26")) + print(float("36.5")) + # Convertir une valeur en chaîne + print(str(36.5)) + # Convertir une valeur complexe en chaîne + print(str([1, 2, 3, 4, 5])) + # Convertir un entier en valeur hexadécimale + print(hex(571)) + + # Conversions mathématiques + print(round(2.5)) + print(round(2.45678, 1)) + print(round(2.45678, 2)) + + # Les valeurs dites fausses + print("Conversions booléennes qui renvoient faux") + print(bool(None)) + print(bool(0)) + print(bool("")) + print(bool(False)) + print(bool([])) + + # Les valeurs dites vraies (autres que les valeurs fausses) + print("Conversions booléennes qui renvoient vrai") + print(bool(1)) # nombre non nul + print(bool(-1)) # nombre non nul + print(bool("Bonjour")) # chaîne non vide + print(bool(True)) + print(bool([1, 3, 5, 7, 9])) # liste non vide + + +if __name__ == "__main__": + base_conversions() diff --git a/source/02-language-basics/variables-expressions-types/source/enumeration.py b/source/02-language-basics/variables-expressions-types/source/enumeration.py new file mode 100644 index 0000000..f4ab956 --- /dev/null +++ b/source/02-language-basics/variables-expressions-types/source/enumeration.py @@ -0,0 +1,3 @@ +seq = [25, 40, 55, 19] +for idx, number in enumerate(seq, start=1): + print(f"Itération {idx} : {number}.") diff --git a/source/02-language-basics/variables-expressions-types/source/introspection_functions.py b/source/02-language-basics/variables-expressions-types/source/introspection_functions.py new file mode 100644 index 0000000..fd223ee --- /dev/null +++ b/source/02-language-basics/variables-expressions-types/source/introspection_functions.py @@ -0,0 +1,30 @@ + +def builtin_introspection(): + """ + Test des fonctions natives d'introspection de Python. + + Ici on teste les fonctions accessibles sans faire d'import, + et qui permettent d'en savoir plus sur l'état du programme ou de + ses variables. + + """ + data1 = "chaîne de caractères" + # Fonction pour vérifier le type d'une variable + print(isinstance(data1, str)) + print(issubclass(str, object)) + print(issubclass(str, int)) + print(type(data1)) + # Fonction pour accéder aux attributs d'une variable + print(hasattr(data1, "manger")) + print(hasattr(data1, "upper")) + print(getattr(data1, "upper")) + # Fonctions pour accéder à toutes les variables locales ou globales + print(locals()) + print(globals()) + # Fonction qui affiche le texte d'aide pour une fonction, méthode etc. + print(help(data1)) + print(help(data1.upper)) + + +if __name__ == "__main__": + builtin_introspection() diff --git a/source/02-language-basics/variables-expressions-types/source/list_functions.py b/source/02-language-basics/variables-expressions-types/source/list_functions.py new file mode 100644 index 0000000..7f65ac9 --- /dev/null +++ b/source/02-language-basics/variables-expressions-types/source/list_functions.py @@ -0,0 +1,34 @@ + +def base_iterable_tests(): + """ + Fonctions de base de python utilisables sur les itérables. + + """ + # Tester any, all + iterable1 = [0, 1, 0, 1, 0, 1] + iterable2 = [0, 0, 0, 0, 0, 0] + iterable3 = [1, 1, 1, 1, 1, 1] + iterable4 = [0, 1, 2, 3, 4, 5] + iterable5 = ["a", "b", "c", "d", "e", "f"] + # Vérifier que toutes les valeurs sont "vraies" + print(all(iterable1)) + print(all(iterable3)) + # Vérifier qu'au moins une valeur est vraie + print(any(iterable1)) + print(any(iterable2)) + print(any(iterable4)) + # Vérifier la longueur de l'itérable + print(len(iterable1)) + + # Calculer la somme des éléments + print(sum(iterable1)) + print(sum(iterable4)) + # Trouver la valeur minimale/maximale des éléments + print(min(iterable4)) + print(max(iterable4)) + print(min(iterable5)) + print(max(iterable5)) + + +if __name__ == "__main__": + base_iterable_tests() diff --git a/source/02-language-basics/variables-expressions-types/source/variable_declaration.py b/source/02-language-basics/variables-expressions-types/source/variable_declaration.py new file mode 100644 index 0000000..2cb9f78 --- /dev/null +++ b/source/02-language-basics/variables-expressions-types/source/variable_declaration.py @@ -0,0 +1,16 @@ +"""Example module for variable declaration.""" + +if __name__ == '__main__': + # Define simple variables + integer1 = 15 # integer value + float1 = 15.0 # floating value + text1 = "Simple text" # string value + boolean1 = True # boolean value + undefined1 = None # special None value + + # Display variable contents + print(integer1) + print(float1) + print(text1) + print(boolean1) + print(undefined1) diff --git a/source/03-exceptions/exceptions/source/base.py b/source/03-exceptions/exceptions/source/base.py new file mode 100644 index 0000000..511ce8c --- /dev/null +++ b/source/03-exceptions/exceptions/source/base.py @@ -0,0 +1,62 @@ +def base_exception_handling(): + """Code de base pour gérer une exception.""" + try: + 15 / 0 + except ZeroDivisionError: + print("Nous avons eu une erreur de division par zéro !") + except Exception: + print("Exception non prise en charge !") + + +def exception_with_else(): + """ + Gérer une exception, avec la clause else. + + La clause else contient du code qui est exécuté si tout se passe + bien. + + """ + try: + 15 / 1 + except ZeroDivisionError: + print("Division par zéro !") + else: + print("Tout s'est bien passé !") + + +def exception_with_finally(): + """ + Gérer une exception, avec la clause finally. + + Le bloc de la clause finally est toujours exécuté, + quand une exception est levée ou que tout se passe bien. + le bloc finally est même exécuté si vous essayez de faire un + `return` dans votre bloc `try`, alors que pourtant la directive + `return` interrompt normalement l'exécution de la fonction. + Cas de figure : fermer un fichier ouvert quoi qu'il arrive. + + """ + try: + 15 / 0 + except ZeroDivisionError: + print("Division par zéro !") + return None + finally: + print("Pas si vite, monsieur return !") + + +def raise_exception(): + """ + Lever manuellement une exception simple. + + Si vous voyez une erreur dans la console, c'est normal. + + """ + raise ValueError("Valeur incorrecte.") + + +if __name__ == "__main__": + base_exception_handling() + exception_with_else() + exception_with_finally() + raise_exception() diff --git a/source/06-extra-types/dates/__init__.py b/source/06-extra-types/dates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/06-extra-types/dates/basedate.py b/source/06-extra-types/dates/basedate.py new file mode 100644 index 0000000..3299b9a --- /dev/null +++ b/source/06-extra-types/dates/basedate.py @@ -0,0 +1,56 @@ +from datetime import date, datetime, timezone + + +def base_dates(): + """ + Gérer des dates de base. + + """ + # Créer deux dates + today = date.today() + before = date(2018, 7, 15) # 15 juillet 2018 + # Afficher la date du jour, et aussi la formater + print(f"Aujourd'hui nous sommes le {today}") + print(f"Aujourd'hui nous sommes le (formaté) {today:%d/%m/%Y}") + # Afficher la date initialisée manuellement + print(f"La finale de Coupe du monde de football a eu lieu le {before}") + + +def base_datetimes(): + """ + Gérer des dates avec heure. + + """ + # Créer deux moments dans le temps + now = datetime.now() + before = datetime(2018, 7, 15, 20, 0) # 15 juillet 2018 à 20h + # Afficher la date du jour, et aussi la formater + print(f"Maintenant nous sommes le {now}") + print(f"Maintenant nous sommes le (formaté) {now:%d/%m/%Y %H:%M:%S}") + # Afficher la date initialisée manuellement + print(f"La finale de Coupe du monde de football a eu lieu à {before}") + + +def timezone_datetimes(): + """ + Gérer des dates avec heure, et avec fuseau horaire. + + """ + now = datetime.now(timezone.utc) + before = datetime(2018, 7, 15, 20, 0, tzinfo=timezone.utc) # 15 juillet 2018 à 20h + # Afficher la date du jour, et aussi la formater + # Voir https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes + print(f"Maintenant nous sommes le {now}") + print(f"Maintenant nous sommes le (formaté) {now:%d/%m/%Y %H:%M:%S (%Z)}") + # Afficher la date initialisée manuellement + print(f"La finale de Coupe du monde de football a eu lieu à {before}") + + +if __name__ == "__main__": + # Lancer la fonction qui teste des dates + base_dates() + # Lancer la fonction qui teste des dates avec heure + base_datetimes() + # Lancer la fonction qui teste des dates avec heure et fuseau horaire + timezone_datetimes() + diff --git a/source/06-extra-types/dates/timedeltas.py b/source/06-extra-types/dates/timedeltas.py new file mode 100644 index 0000000..1bcbee4 --- /dev/null +++ b/source/06-extra-types/dates/timedeltas.py @@ -0,0 +1,21 @@ +from datetime import datetime, timedelta + + +def base_datetime_timedelta(): + """ + Gérer des dates avec heure et ajouter des intervalles de temps. + + """ + # Créer deux moments dans le temps + now: datetime = datetime.now() + interval: timedelta = timedelta(hours=6) + in_six_hours: datetime = now + interval + # Afficher la date du jour, et aussi la formater + print(f"Dans 6 heures on sera le (formaté) {in_six_hours:%d/%m/%Y %H:%M:%S}") + # Afficher la représentation texte de l'intervalle + print(f"L'intervalle de temps est {interval}") + + +if __name__ == "__main__": + # Lancer la fonction qui teste des dates + base_datetime_timedelta() diff --git a/source/07-objects/inheritance/__init__.py b/source/07-objects/inheritance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/07-objects/inheritance/aggregation.py b/source/07-objects/inheritance/aggregation.py new file mode 100644 index 0000000..f03a1de --- /dev/null +++ b/source/07-objects/inheritance/aggregation.py @@ -0,0 +1,115 @@ +from typing import List, Set + + +class User(object): + """ + Classe représentant un utilisateur. + + """ + name: str = None + first_name: str = None + email: str = None + password: str = None + + def __init__(self, name, first_name, email, password): + """ + Initialiser un nouvel utilisateur. + + Args: + name: nom + first_name: prénom + email: email + password: mot de passe + + """ + self.name = name + self.first_name = first_name + self.email = email + self.password = password + + def __repr__(self): + """ + Texte affiché pour l'objet quand on le passe dans `print()` ou surtout + que sa représentation textuelle est demandée. + + Returns: + Le nom de l'utilisateur. + + """ + return self.name + + +class Group(object): + """ + Classe de groupe d'utilisateurs. + + """ + name: str = None + description: str = None + # Ici on a un attribut qui est une liste d'objets d'une autre classe. + # C'est ce qu'on appelle l'agrégation. + # Si on supprime le groupe, les objets utilisateurs existent toujours indépendamment, + # on a ici simplement un lien vers des utilisateurs. + users: Set[User] = None + + def __init__(self, name, description=None): + """ + Initialiser un nouveau groupe d'utilisateurs. + + Args: + name: nom du groupe + description: texte descriptif, facultatif + + """ + self.name = name + self.description = description + + def __repr__(self): + """ + Texte affiché pour l'objet quand on le passe dans `print()` + + Returns: + Le nom du groupe. + + """ + return self.name + + def add_user(self, user: User): + """ + Ajouter un utilisateur au groupe. + + Args: + user: instance d'utilisateur à ajouter + + """ + self.users = self.users or set() + self.users.add(user) + + def get_users(self): + """ + Renvoie la liste des utilisateurs dans le groupe. + + Returns: + La liste des utilisateurs ajoutés au groupe. + + """ + return self.users + + +if __name__ == "__main__": + # Créer quelques utilisateurs + user1 = User("Martin", "Jacques", "jmartin@example.com", "jmartin") + user2 = User("Carletti", "Audrey", "acarletti@example.com", "acarletti") + user3 = User("Richard", "Luc", "lrichard@example.com", "lrichard") + user4 = User("Havel", "Vaclav", "vhavel@example.com", "vhavel") + # Créer un groupe ou deux + group1 = Group("Amicale des amateurs de froid") + group2 = Group("Amicale des amateurs de chaud") + # Ajouter des utilisateurs aux groupes + group1.add_user(user1) + group1.add_user(user2) + group1.add_user(user3) + group2.add_user(user4) + # Afficher les utilisateurs pour chaque groupe + print(f"Utilisateurs du groupe {group1.name} : {group1.get_users()}") + print(f"Utilisateurs du groupe {group2.name} : {group2.get_users()}") \ No newline at end of file diff --git a/source/07-objects/inheritance/multiple.py b/source/07-objects/inheritance/multiple.py new file mode 100644 index 0000000..e69de29 diff --git a/source/07-objects/inheritance/polymorphism.py b/source/07-objects/inheritance/polymorphism.py new file mode 100644 index 0000000..a452c37 --- /dev/null +++ b/source/07-objects/inheritance/polymorphism.py @@ -0,0 +1,64 @@ +from typing import Optional + + +class Animal(object): + """ + Classe de base pour tous les animaux. + + """ + pattes: int = None + vertebre: Optional[bool] = None + + def manger(self): + """ + Méthode de base pour que l'animal mange. + + On ne définit aucun comportement particulier ici. + + """ + print("Je suis un animal et je mange.") + + +class Chien(Animal): + """ + Classe pour le chien. + + """ + pattes: int = 4 + vertebre = True + + def manger(self): + """ + Méthode pour faire manger le chien. + + """ + super().manger() # Exécute le code ligne 19 + print("Je dirais même plus *wouf* ! Je suis un chien qui mange.") + + +class Escargot(Animal): + """ + Classe pour l'escargot. + + """ + pattes: int = 0 + vertebre = False + + def manger(self): + """ + Méthode pour faire manger l'escargot. + + """ + print("Slurp *mange, mais on ne sait pas comment*") + + +if __name__ == "__main__": + # Créer des nouvelles instances d'animaux + escargot = Escargot() + chien = Chien() + # Et voir comment ça se comporte quand on appelle la méthode `manger`. + # Le fait que plusieurs classes héritant d'une autre classe ont des comportements + # différents pour les mêmes méthodes s'appelle du polymorphisme. + # Les méthodes peuvent aussi avoir des arguments différents mais le même nom. + print(escargot.manger()) + print(chien.manger()) diff --git a/source/07-objects/inheritance/simple.py b/source/07-objects/inheritance/simple.py new file mode 100644 index 0000000..c1fe493 --- /dev/null +++ b/source/07-objects/inheritance/simple.py @@ -0,0 +1,92 @@ + +class Person(object): + """ + Classe représentant une personne. + + """ + nom: str = None + prenom: str = None + age: int = None + + def __init__(self, *_args, **kwargs): + """ + Initialiser les valeurs d'une nouvelle personne. + + Args: + *_args: Liste d'arguments non positionnels + **kwargs: Arguments nommés, utilisés pour initialiser les attributs de notre objet. + + """ + self.nom = kwargs.get("nom", None) + self.prenom = kwargs.get("prenom", None) + self.age = kwargs.get("age", None) + + def set_nom_complet(self, nom, prenom): + """ + Méthode pour définir les noms et prénom de l'individu. + + Args: + nom: Nom de famille à attribuer + prenom: Prénom à attribuer à l'objet + + """ + self.prenom = prenom + self.nom = nom + + def get_nom_complet(self): + """ + Méthode pour retrouver d'un coup le nom complet de l'individu. + + Returns: + Nom complet, sous la forme " " + + """ + if self.prenom and self.nom: + return f"{self.prenom} {self.nom}" + else: + return "Nom complet non renseigné" + + +class Professional(Person): + """ + Classe représentant un professionel, héritant de `Person`. + + """ + telephone_pro: str = None + job: str = None + + def __init__(self, *_args, **kwargs): + """ + Initialiser les données d'un nouveau professionel. + + On peut également initialiser le prénom, nom et âge. + + Args: + *_args: Liste d'arguments non positionnels + **kwargs: Liste d'arguments nommés, utilisés pour initialiser les attributs de notre objet. + + """ + super().__init__(*_args, **kwargs) + self.telephone_pro = kwargs.get("telephone_pro", None) + self.job = kwargs.get("job", None) + + def get_nom_complet(self): + """ + Méthode pour retrouver d'un coup le nom complet de l'individu. + + Returns: + Nom complet, sous la forme " " + + """ + base_nom = super().get_nom_complet() + return f"{base_nom} ({self.job})" + + +if __name__ == "__main__": + # Ici on se crée plusieurs objets, 2 professionnels et une personne + pro1 = Professional(nom="Mario", prenom="Mario", age=38, telephone_pro="0799999999", job="Jardinier") + pro2 = Professional(nom="Mario", prenom="Luigi", age=37, telephone_pro="0799999999", job="Plombier") + mec = Person(nom="Bertrand", prenom="Julien", age=30) + # Les deux classe Person et Professional ont des méthodes `get_nom_complet()` différentes, tester + print(mec.get_nom_complet()) + print(pro1.get_nom_complet()) diff --git a/source/07-objects/introspection/__init__.py b/source/07-objects/introspection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/07-objects/introspection/base.py b/source/07-objects/introspection/base.py new file mode 100644 index 0000000..8b7dcbe --- /dev/null +++ b/source/07-objects/introspection/base.py @@ -0,0 +1,42 @@ +import pdir + + +def use_dir(): + """ + Découvrir l'introspection via la fonction `dir()` + + Nécessite pdir2 pour montrer une sortie plus sympa aux étudiants. + + """ + # En python, tout est un objet, et a donc des attributs et des méthodes. + # Le truc bien, c'est qu'en Python, on peut aussi manipuler et retrouver les + # propriétés de ces attributs et méthodes. + chaine = "Bonjour" + # À la place de `pdir` on pouvait utiliser `dir` qui fait partie de python, + # mais qui affiche la liste des attributs de l'objet de façon beaucoup moins + # lisible. + print(pdir(chaine)) + + +def check_attrs(): + """ + Via l'introspection, accéder à des attributs d'objets programmatiquement. + + """ + chaine = "Bonjour" + # Une chaîne a toujours une méthode `capitalize`, donc ça va fonctionner + if hasattr(chaine, "capitalize"): + print("L'objet a bien une fonction `capitalize`.") + print(getattr(chaine, "capitalize")) + # Mais une chaîne n'a pas d'attribut `doesnotexist`. + if hasattr(chaine, "doesnotexist"): + print("L'objet a un attribut `doesnotexist`.") + else: + print("L'objet n'a pas d'attribut `doesnotexist`.") + + +if __name__ == "__main__": + print("Utilisation de la fonction `dir` :") + use_dir() + print("Utilisation de l'introspection d'attributs :") + check_attrs() diff --git a/source/07-objects/magics/__init__.py b/source/07-objects/magics/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/07-objects/magics/deletion.py b/source/07-objects/magics/deletion.py new file mode 100644 index 0000000..843b872 --- /dev/null +++ b/source/07-objects/magics/deletion.py @@ -0,0 +1,11 @@ +class DelTest: + def __del__(self): + print("Suppression.") + + +a = DelTest() +b = a + +# On s'attend à afficher Suppression avant d'afficher la référence de b. +del a +print(b) diff --git a/source/08-text-files/csv/csvread.py b/source/08-text-files/csv/csvread.py new file mode 100644 index 0000000..8e00163 --- /dev/null +++ b/source/08-text-files/csv/csvread.py @@ -0,0 +1,6 @@ +import csv + +with open("demo-file-985.csv", "r", encoding="utf-8") as f: + reader = csv.reader(f) + for row in reader: # row sera une séquence, contenant un élement par colonne de la ligne en cours + print(row) # Affiche la ligne courante du CSV séparée dans une liste. diff --git a/source/08-text-files/csv/demo-file-985.csv b/source/08-text-files/csv/demo-file-985.csv new file mode 100644 index 0000000..c8a89ed --- /dev/null +++ b/source/08-text-files/csv/demo-file-985.csv @@ -0,0 +1 @@ +street,city,zip,state,beds,baths,sq__ft,type,sale_date,price,latitude,longitude 3526 HIGH ST,SACRAMENTO,95838,CA,2,1,836,Residential,Wed May 21 00:00:00 EDT 2008,59222,38.631913,-121.434879 51 OMAHA CT,SACRAMENTO,95823,CA,3,1,1167,Residential,Wed May 21 00:00:00 EDT 2008,68212,38.478902,-121.431028 2796 BRANCH ST,SACRAMENTO,95815,CA,2,1,796,Residential,Wed May 21 00:00:00 EDT 2008,68880,38.618305,-121.443839 2805 JANETTE WAY,SACRAMENTO,95815,CA,2,1,852,Residential,Wed May 21 00:00:00 EDT 2008,69307,38.616835,-121.439146 6001 MCMAHON DR,SACRAMENTO,95824,CA,2,1,797,Residential,Wed May 21 00:00:00 EDT 2008,81900,38.51947,-121.435768 5828 PEPPERMILL CT,SACRAMENTO,95841,CA,3,1,1122,Condo,Wed May 21 00:00:00 EDT 2008,89921,38.662595,-121.327813 6048 OGDEN NASH WAY,SACRAMENTO,95842,CA,3,2,1104,Residential,Wed May 21 00:00:00 EDT 2008,90895,38.681659,-121.351705 2561 19TH AVE,SACRAMENTO,95820,CA,3,1,1177,Residential,Wed May 21 00:00:00 EDT 2008,91002,38.535092,-121.481367 11150 TRINITY RIVER DR Unit 114,RANCHO CORDOVA,95670,CA,2,2,941,Condo,Wed May 21 00:00:00 EDT 2008,94905,38.621188,-121.270555 7325 10TH ST,RIO LINDA,95673,CA,3,2,1146,Residential,Wed May 21 00:00:00 EDT 2008,98937,38.700909,-121.442979 645 MORRISON AVE,SACRAMENTO,95838,CA,3,2,909,Residential,Wed May 21 00:00:00 EDT 2008,100309,38.637663,-121.45152 4085 FAWN CIR,SACRAMENTO,95823,CA,3,2,1289,Residential,Wed May 21 00:00:00 EDT 2008,106250,38.470746,-121.458918 2930 LA ROSA RD,SACRAMENTO,95815,CA,1,1,871,Residential,Wed May 21 00:00:00 EDT 2008,106852,38.618698,-121.435833 2113 KIRK WAY,SACRAMENTO,95822,CA,3,1,1020,Residential,Wed May 21 00:00:00 EDT 2008,107502,38.482215,-121.492603 4533 LOCH HAVEN WAY,SACRAMENTO,95842,CA,2,2,1022,Residential,Wed May 21 00:00:00 EDT 2008,108750,38.672914,-121.35934 7340 HAMDEN PL,SACRAMENTO,95842,CA,2,2,1134,Condo,Wed May 21 00:00:00 EDT 2008,110700,38.700051,-121.351278 6715 6TH ST,RIO LINDA,95673,CA,2,1,844,Residential,Wed May 21 00:00:00 EDT 2008,113263,38.689591,-121.452239 6236 LONGFORD DR Unit 1,CITRUS HEIGHTS,95621,CA,2,1,795,Condo,Wed May 21 00:00:00 EDT 2008,116250,38.679776,-121.314089 250 PERALTA AVE,SACRAMENTO,95833,CA,2,1,588,Residential,Wed May 21 00:00:00 EDT 2008,120000,38.612099,-121.469095 113 LEEWILL AVE,RIO LINDA,95673,CA,3,2,1356,Residential,Wed May 21 00:00:00 EDT 2008,121630,38.689999,-121.46322 6118 STONEHAND AVE,CITRUS HEIGHTS,95621,CA,3,2,1118,Residential,Wed May 21 00:00:00 EDT 2008,122000,38.707851,-121.320707 4882 BANDALIN WAY,SACRAMENTO,95823,CA,4,2,1329,Residential,Wed May 21 00:00:00 EDT 2008,122682,38.468173,-121.444071 7511 OAKVALE CT,NORTH HIGHLANDS,95660,CA,4,2,1240,Residential,Wed May 21 00:00:00 EDT 2008,123000,38.702792,-121.38221 9 PASTURE CT,SACRAMENTO,95834,CA,3,2,1601,Residential,Wed May 21 00:00:00 EDT 2008,124100,38.628631,-121.488097 3729 BAINBRIDGE DR,NORTH HIGHLANDS,95660,CA,3,2,901,Residential,Wed May 21 00:00:00 EDT 2008,125000,38.701499,-121.37622 3828 BLACKFOOT WAY,ANTELOPE,95843,CA,3,2,1088,Residential,Wed May 21 00:00:00 EDT 2008,126640,38.70974,-121.37377 4108 NORTON WAY,SACRAMENTO,95820,CA,3,1,963,Residential,Wed May 21 00:00:00 EDT 2008,127281,38.537526,-121.478315 1469 JANRICK AVE,SACRAMENTO,95832,CA,3,2,1119,Residential,Wed May 21 00:00:00 EDT 2008,129000,38.476472,-121.501711 9861 CULP WAY,SACRAMENTO,95827,CA,4,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,131200,38.558423,-121.327948 7825 CREEK VALLEY CIR,SACRAMENTO,95828,CA,3,2,1248,Residential,Wed May 21 00:00:00 EDT 2008,132000,38.472122,-121.404199 5201 LAGUNA OAKS DR Unit 140,ELK GROVE,95758,CA,2,2,1039,Condo,Wed May 21 00:00:00 EDT 2008,133000,38.423251,-121.444489 6768 MEDORA DR,NORTH HIGHLANDS,95660,CA,3,2,1152,Residential,Wed May 21 00:00:00 EDT 2008,134555,38.691161,-121.37192 3100 EXPLORER DR,SACRAMENTO,95827,CA,3,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,136500,38.566663,-121.332644 7944 DOMINION WAY,ELVERTA,95626,CA,3,2,1116,Residential,Wed May 21 00:00:00 EDT 2008,138750,38.713182,-121.411227 5201 LAGUNA OAKS DR Unit 162,ELK GROVE,95758,CA,2,2,1039,Condo,Wed May 21 00:00:00 EDT 2008,141000,38.423251,-121.444489 3920 SHINING STAR DR,SACRAMENTO,95823,CA,3,2,1418,Residential,Wed May 21 00:00:00 EDT 2008,146250,38.48742,-121.462459 5031 CORVAIR ST,NORTH HIGHLANDS,95660,CA,3,2,1082,Residential,Wed May 21 00:00:00 EDT 2008,147308,38.658246,-121.375469 7661 NIXOS WAY,SACRAMENTO,95823,CA,4,2,1472,Residential,Wed May 21 00:00:00 EDT 2008,148750,38.479553,-121.463317 7044 CARTHY WAY,SACRAMENTO,95828,CA,4,2,1146,Residential,Wed May 21 00:00:00 EDT 2008,149593,38.49857,-121.420925 2442 LARKSPUR LN,SACRAMENTO,95825,CA,1,1,760,Condo,Wed May 21 00:00:00 EDT 2008,150000,38.58514,-121.403736 4800 WESTLAKE PKWY Unit 2109,SACRAMENTO,95835,CA,2,2,1304,Condo,Wed May 21 00:00:00 EDT 2008,152000,38.658812,-121.542345 2178 63RD AVE,SACRAMENTO,95822,CA,3,2,1207,Residential,Wed May 21 00:00:00 EDT 2008,154000,38.493955,-121.48966 8718 ELK WAY,ELK GROVE,95624,CA,3,2,1056,Residential,Wed May 21 00:00:00 EDT 2008,156896,38.41653,-121.379653 5708 RIDGEPOINT DR,ANTELOPE,95843,CA,2,2,1043,Residential,Wed May 21 00:00:00 EDT 2008,161250,38.72027,-121.331555 7315 KOALA CT,NORTH HIGHLANDS,95660,CA,4,2,1587,Residential,Wed May 21 00:00:00 EDT 2008,161500,38.699251,-121.371414 2622 ERIN DR,SACRAMENTO,95833,CA,4,1,1120,Residential,Wed May 21 00:00:00 EDT 2008,164000,38.613765,-121.488694 8421 SUNBLAZE WAY,SACRAMENTO,95823,CA,4,2,1580,Residential,Wed May 21 00:00:00 EDT 2008,165000,38.450543,-121.432538 7420 ALIX PKWY,SACRAMENTO,95823,CA,4,1,1955,Residential,Wed May 21 00:00:00 EDT 2008,166357,38.489405,-121.452811 3820 NATOMA WAY,SACRAMENTO,95838,CA,4,2,1656,Residential,Wed May 21 00:00:00 EDT 2008,166357,38.636748,-121.422159 4431 GREEN TREE DR,SACRAMENTO,95823,CA,3,2,1477,Residential,Wed May 21 00:00:00 EDT 2008,168000,38.499954,-121.454469 9417 SARA ST,ELK GROVE,95624,CA,3,2,1188,Residential,Wed May 21 00:00:00 EDT 2008,170000,38.415518,-121.370527 8299 HALBRITE WAY,SACRAMENTO,95828,CA,4,2,1590,Residential,Wed May 21 00:00:00 EDT 2008,173000,38.473814,-121.4 7223 KALLIE KAY LN,SACRAMENTO,95823,CA,3,2,1463,Residential,Wed May 21 00:00:00 EDT 2008,174250,38.477553,-121.419463 8156 STEINBECK WAY,SACRAMENTO,95828,CA,4,2,1714,Residential,Wed May 21 00:00:00 EDT 2008,174313,38.474853,-121.406326 7957 VALLEY GREEN DR,SACRAMENTO,95823,CA,3,2,1185,Residential,Wed May 21 00:00:00 EDT 2008,178480,38.465184,-121.434925 1122 WILD POPPY CT,GALT,95632,CA,3,2,1406,Residential,Wed May 21 00:00:00 EDT 2008,178760,38.287789,-121.294715 4520 BOMARK WAY,SACRAMENTO,95842,CA,4,2,1943,Multi-Family,Wed May 21 00:00:00 EDT 2008,179580,38.665724,-121.358576 9012 KIEFER BLVD,SACRAMENTO,95826,CA,3,2,1172,Residential,Wed May 21 00:00:00 EDT 2008,181000,38.547011,-121.366217 5332 SANDSTONE ST,CARMICHAEL,95608,CA,3,1,1152,Residential,Wed May 21 00:00:00 EDT 2008,181872,38.662105,-121.313945 5993 SAWYER CIR,SACRAMENTO,95823,CA,4,3,1851,Residential,Wed May 21 00:00:00 EDT 2008,182587,38.4473,-121.435218 4844 CLYDEBANK WAY,ANTELOPE,95843,CA,3,2,1215,Residential,Wed May 21 00:00:00 EDT 2008,182716,38.714609,-121.347887 306 CAMELLIA WAY,GALT,95632,CA,3,2,1130,Residential,Wed May 21 00:00:00 EDT 2008,182750,38.260443,-121.297864 9021 MADISON AVE,ORANGEVALE,95662,CA,4,2,1603,Residential,Wed May 21 00:00:00 EDT 2008,183200,38.664186,-121.217511 404 6TH ST,GALT,95632,CA,3,1,1479,Residential,Wed May 21 00:00:00 EDT 2008,188741,38.251808,-121.302493 8317 SUNNY CREEK WAY,SACRAMENTO,95823,CA,3,2,1420,Residential,Wed May 21 00:00:00 EDT 2008,189000,38.459041,-121.424644 2617 BASS CT,SACRAMENTO,95826,CA,3,2,1280,Residential,Wed May 21 00:00:00 EDT 2008,192067,38.560767,-121.377471 7005 TIANT WAY,ELK GROVE,95758,CA,3,2,1586,Residential,Wed May 21 00:00:00 EDT 2008,194000,38.422811,-121.423285 7895 CABER WAY,ANTELOPE,95843,CA,3,2,1362,Residential,Wed May 21 00:00:00 EDT 2008,194818,38.711279,-121.393449 7624 BOGEY CT,SACRAMENTO,95828,CA,4,4,2162,Multi-Family,Wed May 21 00:00:00 EDT 2008,195000,38.48009,-121.415102 6930 HAMPTON COVE WAY,SACRAMENTO,95823,CA,3,2,1266,Residential,Wed May 21 00:00:00 EDT 2008,198000,38.44004,-121.421012 8708 MESA BROOK WAY,ELK GROVE,95624,CA,4,2,1715,Residential,Wed May 21 00:00:00 EDT 2008,199500,38.44076,-121.385792 120 GRANT LN,FOLSOM,95630,CA,3,2,1820,Residential,Wed May 21 00:00:00 EDT 2008,200000,38.687742,-121.17104 5907 ELLERSLEE DR,CARMICHAEL,95608,CA,3,1,936,Residential,Wed May 21 00:00:00 EDT 2008,200000,38.664468,-121.32683 17 SERASPI CT,SACRAMENTO,95834,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,206000,38.631481,-121.50188 170 PENHOW CIR,SACRAMENTO,95834,CA,3,2,1511,Residential,Wed May 21 00:00:00 EDT 2008,208000,38.653439,-121.535169 8345 STAR THISTLE WAY,SACRAMENTO,95823,CA,4,2,1590,Residential,Wed May 21 00:00:00 EDT 2008,212864,38.454349,-121.439239 9080 FRESCA WAY,ELK GROVE,95758,CA,4,2,1596,Residential,Wed May 21 00:00:00 EDT 2008,221000,38.427818,-121.424026 391 NATALINO CIR,SACRAMENTO,95835,CA,2,2,1341,Residential,Wed May 21 00:00:00 EDT 2008,221000,38.67307,-121.506373 8373 BLACKMAN WAY,ELK GROVE,95624,CA,5,3,2136,Residential,Wed May 21 00:00:00 EDT 2008,223058,38.435436,-121.394536 9837 CORTE DORADO CT,ELK GROVE,95624,CA,4,2,1616,Residential,Wed May 21 00:00:00 EDT 2008,227887,38.400676,-121.38101 5037 J PKWY,SACRAMENTO,95823,CA,3,2,1478,Residential,Wed May 21 00:00:00 EDT 2008,231477,38.491399,-121.443547 10245 LOS PALOS DR,RANCHO CORDOVA,95670,CA,3,2,1287,Residential,Wed May 21 00:00:00 EDT 2008,234697,38.593699,-121.31089 6613 NAVION DR,CITRUS HEIGHTS,95621,CA,4,2,1277,Residential,Wed May 21 00:00:00 EDT 2008,235000,38.702855,-121.31308 2887 AZEVEDO DR,SACRAMENTO,95833,CA,4,2,1448,Residential,Wed May 21 00:00:00 EDT 2008,236000,38.618457,-121.509439 9186 KINBRACE CT,SACRAMENTO,95829,CA,4,3,2235,Residential,Wed May 21 00:00:00 EDT 2008,236685,38.463355,-121.358936 4243 MIDDLEBURY WAY,MATHER,95655,CA,3,2,2093,Residential,Wed May 21 00:00:00 EDT 2008,237800,38.547991,-121.280483 1028 FALLON PLACE CT,RIO LINDA,95673,CA,3,2,1193,Residential,Wed May 21 00:00:00 EDT 2008,240122,38.693818,-121.441153 4804 NORIKER DR,ELK GROVE,95757,CA,3,2,2163,Residential,Wed May 21 00:00:00 EDT 2008,242638,38.400974,-121.448424 7713 HARVEST WOODS DR,SACRAMENTO,95828,CA,3,2,1269,Residential,Wed May 21 00:00:00 EDT 2008,244000,38.478198,-121.412911 2866 KARITSA AVE,SACRAMENTO,95833,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,244500,38.626671,-121.52597 6913 RICHEVE WAY,SACRAMENTO,95828,CA,3,1,958,Residential,Wed May 21 00:00:00 EDT 2008,244960,38.502519,-121.420769 8636 TEGEA WAY,ELK GROVE,95624,CA,5,3,2508,Residential,Wed May 21 00:00:00 EDT 2008,245918,38.443832,-121.382087 5448 MAIDSTONE WAY,CITRUS HEIGHTS,95621,CA,3,2,1305,Residential,Wed May 21 00:00:00 EDT 2008,250000,38.665395,-121.293288 18 OLLIE CT,ELK GROVE,95758,CA,4,2,1591,Residential,Wed May 21 00:00:00 EDT 2008,250000,38.444909,-121.412345 4010 ALEX LN,CARMICHAEL,95608,CA,2,2,1326,Condo,Wed May 21 00:00:00 EDT 2008,250134,38.637028,-121.312963 4901 MILLNER WAY,ELK GROVE,95757,CA,3,2,1843,Residential,Wed May 21 00:00:00 EDT 2008,254200,38.38692,-121.447349 4818 BRITTNEY LEE CT,SACRAMENTO,95841,CA,4,2,1921,Residential,Wed May 21 00:00:00 EDT 2008,254200,38.653917,-121.34218 5529 LAGUNA PARK DR,ELK GROVE,95758,CA,5,3,2790,Residential,Wed May 21 00:00:00 EDT 2008,258000,38.42568,-121.438062 230 CANDELA CIR,SACRAMENTO,95835,CA,3,2,1541,Residential,Wed May 21 00:00:00 EDT 2008,260000,38.656251,-121.547572 4900 71ST ST,SACRAMENTO,95820,CA,3,1,1018,Residential,Wed May 21 00:00:00 EDT 2008,260014,38.53151,-121.421089 12209 CONSERVANCY WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,263500,38.553867,-121.219141 4236 NATOMAS CENTRAL DR,SACRAMENTO,95834,CA,3,2,1672,Condo,Wed May 21 00:00:00 EDT 2008,265000,38.648879,-121.544023 5615 LUPIN LN,POLLOCK PINES,95726,CA,3,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,265000,38.708315,-120.603872 5625 JAMES WAY,SACRAMENTO,95822,CA,3,1,975,Residential,Wed May 21 00:00:00 EDT 2008,271742,38.523947,-121.484946 7842 LAHONTAN CT,SACRAMENTO,95829,CA,4,3,2372,Residential,Wed May 21 00:00:00 EDT 2008,273750,38.472976,-121.318633 6850 21ST ST,SACRAMENTO,95822,CA,3,2,1446,Residential,Wed May 21 00:00:00 EDT 2008,275086,38.502194,-121.490795 2900 BLAIR RD,POLLOCK PINES,95726,CA,2,2,1284,Residential,Wed May 21 00:00:00 EDT 2008,280908,38.75485,-120.60476 2064 EXPEDITION WAY,SACRAMENTO,95832,CA,4,3,3009,Residential,Wed May 21 00:00:00 EDT 2008,280987,38.474099,-121.490711 2912 NORCADE CIR,SACRAMENTO,95826,CA,8,4,3612,Multi-Family,Wed May 21 00:00:00 EDT 2008,282400,38.559505,-121.364839 9507 SEA CLIFF WAY,ELK GROVE,95758,CA,4,2,2056,Residential,Wed May 21 00:00:00 EDT 2008,285000,38.410992,-121.479043 8882 AUTUMN GOLD CT,ELK GROVE,95624,CA,4,2,1993,Residential,Wed May 21 00:00:00 EDT 2008,287417,38.4439,-121.37255 5322 WHITE LOTUS WAY,ELK GROVE,95757,CA,3,2,1857,Residential,Wed May 21 00:00:00 EDT 2008,291000,38.391538,-121.442596 1838 CASTRO WAY,SACRAMENTO,95818,CA,2,1,1126,Residential,Wed May 21 00:00:00 EDT 2008,292024,38.556098,-121.490787 10158 CRAWFORD WAY,SACRAMENTO,95827,CA,4,4,2213,Multi-Family,Wed May 21 00:00:00 EDT 2008,297000,38.5703,-121.315735 7731 MASTERS ST,ELK GROVE,95758,CA,5,3,2494,Residential,Wed May 21 00:00:00 EDT 2008,297000,38.442031,-121.410873 4925 PERCHERON DR,ELK GROVE,95757,CA,3,2,1843,Residential,Wed May 21 00:00:00 EDT 2008,298000,38.40154,-121.447649 2010 PROMONTORY POINT LN,GOLD RIVER,95670,CA,2,2,1520,Residential,Wed May 21 00:00:00 EDT 2008,299000,38.62869,-121.261669 4727 SAVOIE WAY,SACRAMENTO,95835,CA,5,3,2800,Residential,Wed May 21 00:00:00 EDT 2008,304037,38.658182,-121.549521 8664 MAGNOLIA HILL WAY,ELK GROVE,95624,CA,4,2,2309,Residential,Wed May 21 00:00:00 EDT 2008,311000,38.442352,-121.389675 9570 HARVEST ROSE WAY,SACRAMENTO,95827,CA,5,3,2367,Residential,Wed May 21 00:00:00 EDT 2008,315537,38.555993,-121.340352 4359 CREGAN CT,RANCHO CORDOVA,95742,CA,5,4,3516,Residential,Wed May 21 00:00:00 EDT 2008,320000,38.545128,-121.224922 5337 DUSTY ROSE WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,320000,38.528575,-121.2286 8929 SUTTERS GOLD DR,SACRAMENTO,95826,CA,4,3,1914,Residential,Wed May 21 00:00:00 EDT 2008,328360,38.550848,-121.370224 8025 PEERLESS AVE,ORANGEVALE,95662,CA,2,1,1690,Residential,Wed May 21 00:00:00 EDT 2008,334150,38.71147,-121.216214 4620 WELERA WAY,ELK GROVE,95757,CA,3,3,2725,Residential,Wed May 21 00:00:00 EDT 2008,335750,38.398609,-121.450148 9723 TERRAPIN CT,ELK GROVE,95757,CA,4,3,2354,Residential,Wed May 21 00:00:00 EDT 2008,335750,38.403492,-121.430224 2115 SMOKESTACK WAY,SACRAMENTO,95833,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,339500,38.602416,-121.542965 100 REBECCA WAY,FOLSOM,95630,CA,3,2,2185,Residential,Wed May 21 00:00:00 EDT 2008,344250,38.68479,-121.149199 9488 OAK VILLAGE WAY,ELK GROVE,95758,CA,4,2,1801,Residential,Wed May 21 00:00:00 EDT 2008,346210,38.41333,-121.404999 8495 DARTFORD DR,SACRAMENTO,95823,CA,3,3,1961,Residential,Wed May 21 00:00:00 EDT 2008,347029,38.448507,-121.421346 6708 PONTA DO SOL WAY,ELK GROVE,95757,CA,4,2,3134,Residential,Wed May 21 00:00:00 EDT 2008,347650,38.380635,-121.425538 4143 SEA MEADOW WAY,SACRAMENTO,95823,CA,4,3,1915,Residential,Wed May 21 00:00:00 EDT 2008,351300,38.46534,-121.457519 3020 RICHARDSON CIR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Wed May 21 00:00:00 EDT 2008,352000,38.691299,-121.081752 8082 LINDA ISLE LN,SACRAMENTO,95831,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,370000,38.4772,-121.5215 15300 MURIETA SOUTH PKWY,RANCHO MURIETA,95683,CA,4,3,2734,Residential,Wed May 21 00:00:00 EDT 2008,370500,38.4874,-121.075129 11215 SHARRMONT CT,WILTON,95693,CA,3,2,2110,Residential,Wed May 21 00:00:00 EDT 2008,372000,38.35062,-121.228349 7105 DANBERG WAY,ELK GROVE,95757,CA,5,3,3164,Residential,Wed May 21 00:00:00 EDT 2008,375000,38.4019,-121.420388 5579 JERRY LITELL WAY,SACRAMENTO,95835,CA,5,3,3599,Residential,Wed May 21 00:00:00 EDT 2008,381300,38.677126,-121.500519 1050 FOXHALL WAY,SACRAMENTO,95831,CA,4,2,2054,Residential,Wed May 21 00:00:00 EDT 2008,381942,38.509819,-121.519661 7837 ABBINGTON WAY,ANTELOPE,95843,CA,4,2,1830,Residential,Wed May 21 00:00:00 EDT 2008,387731,38.709873,-121.339472 1300 F ST,SACRAMENTO,95814,CA,3,3,1627,Residential,Wed May 21 00:00:00 EDT 2008,391000,38.58355,-121.487289 6801 RAWLEY WAY,ELK GROVE,95757,CA,4,3,3440,Residential,Wed May 21 00:00:00 EDT 2008,394470,38.408351,-121.423925 1693 SHELTER COVE DR,GREENWOOD,95635,CA,3,2,2846,Residential,Wed May 21 00:00:00 EDT 2008,395000,38.945357,-120.908822 9361 WADDELL LN,ELK GROVE,95624,CA,4,3,2359,Residential,Wed May 21 00:00:00 EDT 2008,400186,38.450829,-121.349928 10 SEA FOAM CT,SACRAMENTO,95831,CA,3,3,2052,Residential,Wed May 21 00:00:00 EDT 2008,415000,38.487885,-121.545947 6945 RIO TEJO WAY,ELK GROVE,95757,CA,5,3,3433,Residential,Wed May 21 00:00:00 EDT 2008,425000,38.385638,-121.422616 4186 TULIP PARK WAY,RANCHO CORDOVA,95742,CA,5,3,3615,Residential,Wed May 21 00:00:00 EDT 2008,430000,38.550617,-121.23526 9278 DAIRY CT,ELK GROVE,95624,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,445000,38.420338,-121.363757 207 ORANGE BLOSSOM CIR Unit C,FOLSOM,95630,CA,5,3,2687,Residential,Wed May 21 00:00:00 EDT 2008,460000,38.646273,-121.175322 6507 RIO DE ONAR WAY,ELK GROVE,95757,CA,4,3,2724,Residential,Wed May 21 00:00:00 EDT 2008,461000,38.38253,-121.428007 7004 RAWLEY WAY,ELK GROVE,95757,CA,4,3,3440,Residential,Wed May 21 00:00:00 EDT 2008,489332,38.406421,-121.422081 6503 RIO DE ONAR WAY,ELK GROVE,95757,CA,5,4,3508,Residential,Wed May 21 00:00:00 EDT 2008,510000,38.38253,-121.428038 2217 APPALOOSA CT,FOLSOM,95630,CA,4,2,2462,Residential,Wed May 21 00:00:00 EDT 2008,539000,38.655167,-121.090178 868 HILDEBRAND CIR,FOLSOM,95630,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,585000,38.670947,-121.097727 6030 PALERMO WAY,EL DORADO HILLS,95762,CA,4,3,0,Residential,Wed May 21 00:00:00 EDT 2008,600000,38.672761,-121.050378 4070 REDONDO DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Wed May 21 00:00:00 EDT 2008,606238,38.666807,-121.06483 4004 CRESTA WAY,SACRAMENTO,95864,CA,3,3,2325,Residential,Wed May 21 00:00:00 EDT 2008,660000,38.591618,-121.370626 315 JUMEL CT,EL DORADO HILLS,95762,CA,6,5,0,Residential,Wed May 21 00:00:00 EDT 2008,830000,38.669931,-121.05958 6272 LONGFORD DR Unit 1,CITRUS HEIGHTS,95621,CA,2,1,795,Condo,Tue May 20 00:00:00 EDT 2008,69000,38.680923,-121.313945 3432 Y ST,SACRAMENTO,95817,CA,4,2,1099,Residential,Tue May 20 00:00:00 EDT 2008,70000,38.554967,-121.468046 9512 EMERALD PARK DR Unit 3,ELK GROVE,95624,CA,2,1,840,Condo,Tue May 20 00:00:00 EDT 2008,71000,38.40573,-121.369832 3132 CLAY ST,SACRAMENTO,95815,CA,2,1,800,Residential,Tue May 20 00:00:00 EDT 2008,78000,38.624678,-121.439203 5221 38TH AVE,SACRAMENTO,95824,CA,2,1,746,Residential,Tue May 20 00:00:00 EDT 2008,78400,38.518044,-121.443555 6112 HERMOSA ST,SACRAMENTO,95822,CA,3,1,1067,Residential,Tue May 20 00:00:00 EDT 2008,80000,38.515125,-121.480416 483 ARCADE BLVD,SACRAMENTO,95815,CA,4,2,1316,Residential,Tue May 20 00:00:00 EDT 2008,89000,38.623571,-121.454884 671 SONOMA AVE,SACRAMENTO,95815,CA,3,1,1337,Residential,Tue May 20 00:00:00 EDT 2008,90000,38.622953,-121.450142 5980 79TH ST,SACRAMENTO,95824,CA,2,1,868,Residential,Tue May 20 00:00:00 EDT 2008,90000,38.518373,-121.411779 7607 ELDER CREEK RD,SACRAMENTO,95824,CA,3,1,924,Residential,Tue May 20 00:00:00 EDT 2008,92000,38.51055,-121.414768 5028 14TH AVE,SACRAMENTO,95820,CA,2,1,610,Residential,Tue May 20 00:00:00 EDT 2008,93675,38.53942,-121.446894 14788 NATCHEZ CT,RANCHO MURIETA,95683,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,97750,38.492287,-121.100032 1069 ACACIA AVE,SACRAMENTO,95815,CA,2,1,1220,Residential,Tue May 20 00:00:00 EDT 2008,98000,38.621998,-121.442238 5201 LAGUNA OAKS DR Unit 199,ELK GROVE,95758,CA,1,1,722,Condo,Tue May 20 00:00:00 EDT 2008,98000,38.423251,-121.444489 3847 LAS PASAS WAY,SACRAMENTO,95864,CA,3,1,1643,Residential,Tue May 20 00:00:00 EDT 2008,99000,38.588672,-121.373916 5201 LAGUNA OAKS DR Unit 172,ELK GROVE,95758,CA,1,1,722,Condo,Tue May 20 00:00:00 EDT 2008,100000,38.423251,-121.444489 1121 CREEKSIDE WAY,GALT,95632,CA,3,1,1080,Residential,Tue May 20 00:00:00 EDT 2008,106716,38.241514,-121.312199 5307 CABRILLO WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Tue May 20 00:00:00 EDT 2008,111000,38.52712,-121.435348 3725 DON JULIO BLVD,NORTH HIGHLANDS,95660,CA,3,1,1051,Residential,Tue May 20 00:00:00 EDT 2008,111000,38.67895,-121.379406 4803 MCCLOUD DR,SACRAMENTO,95842,CA,2,2,967,Residential,Tue May 20 00:00:00 EDT 2008,114800,38.682279,-121.352817 10542 SILVERWOOD WAY,RANCHO CORDOVA,95670,CA,3,1,1098,Residential,Tue May 20 00:00:00 EDT 2008,120108,38.587156,-121.295778 6318 39TH AVE,SACRAMENTO,95824,CA,3,1,1050,Residential,Tue May 20 00:00:00 EDT 2008,123225,38.518942,-121.430158 211 MCDANIEL CIR,SACRAMENTO,95838,CA,3,2,1110,Residential,Tue May 20 00:00:00 EDT 2008,123750,38.636565,-121.460383 3800 LYNHURST WAY,NORTH HIGHLANDS,95660,CA,3,1,888,Residential,Tue May 20 00:00:00 EDT 2008,125000,38.650445,-121.374861 6139 HERMOSA ST,SACRAMENTO,95822,CA,3,2,1120,Residential,Tue May 20 00:00:00 EDT 2008,125000,38.514665,-121.480411 2505 RHINE WAY,ELVERTA,95626,CA,3,2,1080,Residential,Tue May 20 00:00:00 EDT 2008,126000,38.717976,-121.407684 3692 PAYNE WAY,NORTH HIGHLANDS,95660,CA,3,1,957,Residential,Tue May 20 00:00:00 EDT 2008,129000,38.66654,-121.378298 604 MORRISON AVE,SACRAMENTO,95838,CA,2,1,952,Residential,Tue May 20 00:00:00 EDT 2008,134000,38.637678,-121.452476 648 SANTA ANA AVE,SACRAMENTO,95838,CA,3,2,1211,Residential,Tue May 20 00:00:00 EDT 2008,135000,38.658478,-121.450409 14 ASHLEY OAKS CT,SACRAMENTO,95815,CA,3,2,1264,Residential,Tue May 20 00:00:00 EDT 2008,135500,38.61779,-121.436765 3174 NORTHVIEW DR,SACRAMENTO,95833,CA,3,1,1080,Residential,Tue May 20 00:00:00 EDT 2008,140000,38.623817,-121.477827 840 TRANQUIL LN,GALT,95632,CA,3,2,1266,Residential,Tue May 20 00:00:00 EDT 2008,140000,38.270617,-121.299205 5333 PRIMROSE DR Unit 19A,FAIR OAKS,95628,CA,2,2,994,Condo,Tue May 20 00:00:00 EDT 2008,142500,38.662785,-121.276272 1035 MILLET WAY,SACRAMENTO,95834,CA,3,2,1202,Residential,Tue May 20 00:00:00 EDT 2008,143500,38.631056,-121.48508 5201 LAGUNA OAKS DR Unit 126,ELK GROVE,95758,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,145000,38.423251,-121.444489 3328 22ND AVE,SACRAMENTO,95820,CA,2,1,722,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.532727,-121.470783 8001 HARTWICK WAY,SACRAMENTO,95828,CA,4,2,1448,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.488623,-121.410582 7812 HARTWICK WAY,SACRAMENTO,95828,CA,3,2,1188,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.488611,-121.412808 4207 PAINTER WAY,NORTH HIGHLANDS,95660,CA,4,2,1183,Residential,Tue May 20 00:00:00 EDT 2008,146000,38.692915,-121.367497 7458 WINKLEY WAY,SACRAMENTO,95822,CA,3,1,1320,Residential,Tue May 20 00:00:00 EDT 2008,148500,38.487444,-121.491366 8354 SUNRISE WOODS WAY,SACRAMENTO,95828,CA,3,2,1117,Residential,Tue May 20 00:00:00 EDT 2008,149000,38.473288,-121.3963 8116 COTTONMILL CIR,SACRAMENTO,95828,CA,3,2,1364,Residential,Tue May 20 00:00:00 EDT 2008,150000,38.482876,-121.405912 4660 CEDARWOOD WAY,SACRAMENTO,95823,CA,4,2,1310,Residential,Tue May 20 00:00:00 EDT 2008,150000,38.484834,-121.449316 9254 HARROGATE WAY,ELK GROVE,95758,CA,2,2,1006,Residential,Tue May 20 00:00:00 EDT 2008,152000,38.420138,-121.412179 6716 TAREYTON WAY,CITRUS HEIGHTS,95621,CA,3,2,1104,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.693724,-121.307169 2028 ROBERT WAY,SACRAMENTO,95825,CA,2,1,810,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.609982,-121.419263 9346 AIZENBERG CIR,ELK GROVE,95624,CA,2,2,1123,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.41875,-121.370019 4524 LOCH HAVEN WAY,SACRAMENTO,95842,CA,2,1,904,Residential,Tue May 20 00:00:00 EDT 2008,157788,38.67273,-121.359645 7140 BLUE SPRINGS WAY,CITRUS HEIGHTS,95621,CA,3,2,1156,Residential,Tue May 20 00:00:00 EDT 2008,161653,38.720653,-121.302241 4631 11TH AVE,SACRAMENTO,95820,CA,2,1,1321,Residential,Tue May 20 00:00:00 EDT 2008,161829,38.541965,-121.452132 3228 BAGGAN CT,ANTELOPE,95843,CA,3,2,1392,Residential,Tue May 20 00:00:00 EDT 2008,165000,38.715346,-121.388163 8515 DARTFORD DR,SACRAMENTO,95823,CA,3,2,1439,Residential,Tue May 20 00:00:00 EDT 2008,168000,38.448288,-121.420719 4500 TIPPWOOD WAY,SACRAMENTO,95842,CA,3,2,1159,Residential,Tue May 20 00:00:00 EDT 2008,169000,38.69951,-121.359989 2460 EL ROCCO WAY,RANCHO CORDOVA,95670,CA,3,2,1671,Residential,Tue May 20 00:00:00 EDT 2008,175000,38.591477,-121.31534 8244 SUNBIRD WAY,SACRAMENTO,95823,CA,3,2,1740,Residential,Tue May 20 00:00:00 EDT 2008,176250,38.457654,-121.431381 5841 VALLEY VALE WAY,SACRAMENTO,95823,CA,3,2,1265,Residential,Tue May 20 00:00:00 EDT 2008,179000,38.461283,-121.434322 7863 CRESTLEIGH CT,ANTELOPE,95843,CA,2,2,1007,Residential,Tue May 20 00:00:00 EDT 2008,180000,38.710889,-121.358876 7129 SPRINGMONT DR,ELK GROVE,95758,CA,3,2,1716,Residential,Tue May 20 00:00:00 EDT 2008,180400,38.417649,-121.420294 8284 RED FOX WAY,ELK GROVE,95758,CA,4,2,1685,Residential,Tue May 20 00:00:00 EDT 2008,182000,38.417182,-121.397231 2219 EL CANTO CIR,RANCHO CORDOVA,95670,CA,4,2,1829,Residential,Tue May 20 00:00:00 EDT 2008,184500,38.592383,-121.318669 8907 GEMWOOD WAY,ELK GROVE,95758,CA,3,2,1555,Residential,Tue May 20 00:00:00 EDT 2008,185000,38.435471,-121.441173 5925 MALEVILLE AVE,CARMICHAEL,95608,CA,4,2,1120,Residential,Tue May 20 00:00:00 EDT 2008,189000,38.666564,-121.325717 7031 CANEVALLEY CIR,CITRUS HEIGHTS,95621,CA,3,2,1137,Residential,Tue May 20 00:00:00 EDT 2008,194000,38.718693,-121.303619 3949 WILDROSE WAY,SACRAMENTO,95826,CA,3,1,1174,Residential,Tue May 20 00:00:00 EDT 2008,195000,38.543697,-121.366683 4437 MITCHUM CT,ANTELOPE,95843,CA,3,2,1393,Residential,Tue May 20 00:00:00 EDT 2008,200000,38.704407,-121.36113 2778 KAWEAH CT,CAMERON PARK,95682,CA,3,1,0,Residential,Tue May 20 00:00:00 EDT 2008,201000,38.694052,-120.995589 1636 ALLENWOOD CIR,LINCOLN,95648,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,202500,38.879192,-121.309477 8151 QUAIL RIDGE CT,SACRAMENTO,95828,CA,3,2,1289,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.461296,-121.390858 4899 WIND CREEK DR,SACRAMENTO,95838,CA,4,2,1799,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.655887,-121.446119 2370 BIG CANYON CREEK RD,PLACERVILLE,95667,CA,3,2,0,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.74458,-120.794254 6049 HAMBURG WAY,SACRAMENTO,95823,CA,4,3,1953,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.443253,-121.431992 4232 71ST ST,SACRAMENTO,95820,CA,2,1,723,Residential,Tue May 20 00:00:00 EDT 2008,207000,38.536741,-121.42115 3361 BOW MAR CT,CAMERON PARK,95682,CA,2,2,0,Residential,Tue May 20 00:00:00 EDT 2008,210000,38.69437,-120.996602 1889 COLD SPRINGS RD,PLACERVILLE,95667,CA,2,1,948,Residential,Tue May 20 00:00:00 EDT 2008,211500,38.739774,-120.860243 5805 HIMALAYA WAY,CITRUS HEIGHTS,95621,CA,4,2,1578,Residential,Tue May 20 00:00:00 EDT 2008,215000,38.696489,-121.328555 7944 SYLVAN OAK WAY,CITRUS HEIGHTS,95610,CA,3,2,1317,Residential,Tue May 20 00:00:00 EDT 2008,215000,38.710388,-121.261096 3139 SPOONWOOD WAY Unit 1,SACRAMENTO,95833,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,215500,38.626582,-121.52151 6217 LEOLA WAY,SACRAMENTO,95824,CA,3,1,1360,Residential,Tue May 20 00:00:00 EDT 2008,222381,38.513066,-121.451909 2340 HURLEY WAY,SACRAMENTO,95825,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,225000,38.588816,-121.408549 3035 BRUNNET LN,SACRAMENTO,95833,CA,3,2,1522,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.624762,-121.522775 3025 EL PRADO WAY,SACRAMENTO,95825,CA,4,2,1751,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.606603,-121.394147 9387 GRANITE FALLS CT,ELK GROVE,95624,CA,3,2,1465,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.419214,-121.348533 9257 CALDERA WAY,SACRAMENTO,95826,CA,4,2,1605,Residential,Tue May 20 00:00:00 EDT 2008,228000,38.55821,-121.355022 441 ARLINGDALE CIR,RIO LINDA,95673,CA,4,2,1475,Residential,Tue May 20 00:00:00 EDT 2008,229665,38.702893,-121.454949 2284 LOS ROBLES RD,MEADOW VISTA,95722,CA,3,1,1216,Residential,Tue May 20 00:00:00 EDT 2008,230000,39.008159,-121.03623 8164 CHENIN BLANC LN,FAIR OAKS,95628,CA,2,2,1315,Residential,Tue May 20 00:00:00 EDT 2008,230000,38.665644,-121.259969 4620 CHAMBERLIN CIR,ELK GROVE,95757,CA,3,2,1567,Residential,Tue May 20 00:00:00 EDT 2008,230000,38.390557,-121.449805 5340 BIRK WAY,SACRAMENTO,95835,CA,3,2,1776,Residential,Tue May 20 00:00:00 EDT 2008,234000,38.672495,-121.515251 51 ANJOU CIR,SACRAMENTO,95835,CA,3,2,2187,Residential,Tue May 20 00:00:00 EDT 2008,235000,38.661658,-121.540633 2125 22ND AVE,SACRAMENTO,95822,CA,3,1,1291,Residential,Tue May 20 00:00:00 EDT 2008,236250,38.534596,-121.493121 611 BLOSSOM ROCK LN,FOLSOM,95630,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,240000,38.6457,-121.1197 8830 ADUR RD,ELK GROVE,95624,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,242000,38.43742,-121.372876 7344 BUTTERBALL WAY,SACRAMENTO,95842,CA,3,2,1503,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.699489,-121.361828 8219 GWINHURST CIR,SACRAMENTO,95828,CA,4,3,2491,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.459711,-121.384283 3240 S ST,SACRAMENTO,95816,CA,2,1,1269,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.562296,-121.467489 221 PICASSO CIR,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.676658,-121.528128 5706 GREENACRES WAY,ORANGEVALE,95662,CA,3,2,1176,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.669882,-121.213533 6900 LONICERA DR,ORANGEVALE,95662,CA,4,2,1456,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.692199,-121.250975 419 DAWNRIDGE RD,ROSEVILLE,95678,CA,3,2,1498,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.725283,-121.297953 5312 MARBURY WAY,ANTELOPE,95843,CA,3,2,1574,Residential,Tue May 20 00:00:00 EDT 2008,255000,38.710221,-121.341651 6344 BONHAM CIR,CITRUS HEIGHTS,95610,CA,5,4,2085,Multi-Family,Tue May 20 00:00:00 EDT 2008,256054,38.682358,-121.272876 8207 YORKTON WAY,SACRAMENTO,95829,CA,3,2,2170,Residential,Tue May 20 00:00:00 EDT 2008,257729,38.45967,-121.360461 7922 MANSELL WAY,ELK GROVE,95758,CA,4,2,1595,Residential,Tue May 20 00:00:00 EDT 2008,260000,38.409634,-121.410787 5712 MELBURY CIR,ANTELOPE,95843,CA,3,2,1567,Residential,Tue May 20 00:00:00 EDT 2008,261000,38.705849,-121.334701 632 NEWBRIDGE LN,LINCOLN,95648,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,261800,38.879084,-121.298586 1570 GLIDDEN AVE,SACRAMENTO,95822,CA,4,2,1253,Residential,Tue May 20 00:00:00 EDT 2008,264469,38.482704,-121.500433 8108 FILIFERA WAY,ANTELOPE,95843,CA,4,3,1768,Residential,Tue May 20 00:00:00 EDT 2008,265000,38.717042,-121.35468 230 BANKSIDE WAY,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.676937,-121.529244 5342 CALABRIA WAY,SACRAMENTO,95835,CA,4,3,2030,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.671807,-121.498274 47 NAPONEE CT,SACRAMENTO,95835,CA,3,2,1531,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.665704,-121.529096 4236 ADRIATIC SEA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.647961,-121.543162 8864 REMBRANT CT,ELK GROVE,95624,CA,4,3,1653,Residential,Tue May 20 00:00:00 EDT 2008,275000,38.435288,-121.375703 9455 SEA CLIFF WAY,ELK GROVE,95758,CA,4,2,2056,Residential,Tue May 20 00:00:00 EDT 2008,275000,38.411522,-121.481406 9720 LITTLE HARBOR WAY,ELK GROVE,95624,CA,4,3,2494,Residential,Tue May 20 00:00:00 EDT 2008,280000,38.404934,-121.352405 8806 PHOENIX AVE,FAIR OAKS,95628,CA,3,2,1450,Residential,Tue May 20 00:00:00 EDT 2008,286013,38.660322,-121.230101 3578 LOGGERHEAD WAY,SACRAMENTO,95834,CA,4,2,2169,Residential,Tue May 20 00:00:00 EDT 2008,292000,38.633028,-121.526755 1416 LOCKHART WAY,ROSEVILLE,95747,CA,3,2,1440,Residential,Tue May 20 00:00:00 EDT 2008,292000,38.752399,-121.330328 5413 BUENA VENTURA WAY,FAIR OAKS,95628,CA,3,2,1527,Residential,Tue May 20 00:00:00 EDT 2008,293993,38.664552,-121.255937 37 WHITE BIRCH CT,ROSEVILLE,95678,CA,3,2,1401,Residential,Tue May 20 00:00:00 EDT 2008,294000,38.776327,-121.284514 405 MARLIN SPIKE WAY,SACRAMENTO,95838,CA,3,2,1411,Residential,Tue May 20 00:00:00 EDT 2008,296769,38.65783,-121.456842 1102 CHESLEY LN,LINCOLN,95648,CA,4,4,0,Residential,Tue May 20 00:00:00 EDT 2008,297500,38.864864,-121.313988 11281 STANFORD COURT LN Unit 604,GOLD RIVER,95670,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,300000,38.625289,-121.260286 7320 6TH ST,RIO LINDA,95673,CA,3,1,1284,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.700553,-121.452223 993 MANTON CT,GALT,95632,CA,4,3,2307,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.272942,-121.289148 4487 PANORAMA DR,PLACERVILLE,95667,CA,3,2,1329,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.694559,-120.848157 5651 OVERLEAF WAY,SACRAMENTO,95835,CA,4,2,1910,Residential,Tue May 20 00:00:00 EDT 2008,300500,38.677454,-121.494791 2015 PROMONTORY POINT LN,GOLD RIVER,95670,CA,3,2,1981,Residential,Tue May 20 00:00:00 EDT 2008,305000,38.628732,-121.261149 3224 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,306500,38.772771,-121.364877 15 VANESSA PL,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,312500,38.668692,-121.54549 1312 RENISON LN,LINCOLN,95648,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,315000,38.866409,-121.308485 8 RIVER RAFT CT,SACRAMENTO,95823,CA,4,2,2205,Residential,Tue May 20 00:00:00 EDT 2008,319789,38.447353,-121.434969 2251 LAMPLIGHT LN,LINCOLN,95648,CA,2,2,1449,Residential,Tue May 20 00:00:00 EDT 2008,330000,38.849924,-121.275729 106 FARHAM DR,FOLSOM,95630,CA,3,2,1258,Residential,Tue May 20 00:00:00 EDT 2008,330000,38.667834,-121.168578 5405 NECTAR CIR,ELK GROVE,95757,CA,3,2,2575,Residential,Tue May 20 00:00:00 EDT 2008,331000,38.387014,-121.440967 5411 10TH AVE,SACRAMENTO,95820,CA,2,1,539,Residential,Tue May 20 00:00:00 EDT 2008,334000,38.542727,-121.442449 3512 RAINSONG CIR,RANCHO CORDOVA,95670,CA,4,3,2208,Residential,Tue May 20 00:00:00 EDT 2008,336000,38.573488,-121.282809 1106 55TH ST,SACRAMENTO,95819,CA,3,1,1108,Residential,Tue May 20 00:00:00 EDT 2008,339000,38.563805,-121.436395 411 ILLSLEY WAY,FOLSOM,95630,CA,4,2,1595,Residential,Tue May 20 00:00:00 EDT 2008,339000,38.652002,-121.129504 796 BUTTERCUP CIR,GALT,95632,CA,4,2,2159,Residential,Tue May 20 00:00:00 EDT 2008,345000,38.279581,-121.300828 1230 SANDRA CIR,PLACERVILLE,95667,CA,4,3,2295,Residential,Tue May 20 00:00:00 EDT 2008,350000,38.738141,-120.784145 318 ANACAPA DR,ROSEVILLE,95678,CA,3,2,1838,Residential,Tue May 20 00:00:00 EDT 2008,356000,38.782094,-121.297133 3975 SHINING STAR DR,SACRAMENTO,95823,CA,4,2,1900,Residential,Tue May 20 00:00:00 EDT 2008,361745,38.487409,-121.461413 1620 BASLER ST,SACRAMENTO,95811,CA,4,2,1718,Residential,Tue May 20 00:00:00 EDT 2008,361948,38.591822,-121.478644 9688 NATURE TRAIL WAY,ELK GROVE,95757,CA,5,3,3389,Residential,Tue May 20 00:00:00 EDT 2008,370000,38.405224,-121.479275 5924 TANUS CIR,ROCKLIN,95677,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,380000,38.778691,-121.204292 9629 CEDAR OAK WAY,ELK GROVE,95757,CA,5,4,3260,Residential,Tue May 20 00:00:00 EDT 2008,385000,38.405527,-121.431746 3429 FERNBROOK CT,CAMERON PARK,95682,CA,3,2,2016,Residential,Tue May 20 00:00:00 EDT 2008,399000,38.664225,-121.007173 2121 HANNAH WAY,ROCKLIN,95765,CA,4,2,2607,Residential,Tue May 20 00:00:00 EDT 2008,402000,38.805749,-121.280931 10104 ANNIE ST,ELK GROVE,95757,CA,4,3,2724,Residential,Tue May 20 00:00:00 EDT 2008,406026,38.390465,-121.443479 1092 MAUGHAM CT,GALT,95632,CA,5,4,3746,Residential,Tue May 20 00:00:00 EDT 2008,420000,38.271646,-121.286848 5404 ALMOND FALLS WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,425000,38.527502,-121.233492 6306 CONEJO,RANCHO MURIETA,95683,CA,4,2,3192,Residential,Tue May 20 00:00:00 EDT 2008,425000,38.512602,-121.087233 14 CASA VATONI PL,SACRAMENTO,95834,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,433500,38.650221,-121.551704 1456 EAGLESFIELD LN,LINCOLN,95648,CA,4,3,0,Residential,Tue May 20 00:00:00 EDT 2008,436746,38.857635,-121.311375 4100 BOTHWELL CIR,EL DORADO HILLS,95762,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,438700,38.679136,-121.034329 427 21ST ST,SACRAMENTO,95811,CA,2,1,1247,Residential,Tue May 20 00:00:00 EDT 2008,445000,38.582604,-121.47576 1044 GALSTON DR,FOLSOM,95630,CA,4,2,2581,Residential,Tue May 20 00:00:00 EDT 2008,450000,38.676306,-121.09954 4440 SYCAMORE AVE,SACRAMENTO,95841,CA,3,1,2068,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.646374,-121.353658 1032 SOUZA DR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.668239,-121.064437 9760 LAZULITE CT,ELK GROVE,95624,CA,4,3,3992,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.403609,-121.335541 241 LANFRANCO CIR,SACRAMENTO,95835,CA,4,4,3397,Residential,Tue May 20 00:00:00 EDT 2008,465000,38.665696,-121.549437 5559 NORTHBOROUGH DR,SACRAMENTO,95835,CA,5,3,3881,Residential,Tue May 20 00:00:00 EDT 2008,471750,38.677225,-121.519687 2125 BIG SKY DR,ROCKLIN,95765,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,480000,38.801637,-121.278798 2109 HAMLET PL,CARMICHAEL,95608,CA,2,2,1598,Residential,Tue May 20 00:00:00 EDT 2008,484000,38.602754,-121.329326 9970 STATE HIGHWAY 193,PLACERVILLE,95667,CA,4,3,1929,Residential,Tue May 20 00:00:00 EDT 2008,485000,38.787877,-120.816676 2901 PINTAIL WAY,ELK GROVE,95757,CA,4,3,3070,Residential,Tue May 20 00:00:00 EDT 2008,495000,38.398488,-121.473424 201 FIRESTONE DR,ROSEVILLE,95678,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,500500,38.770153,-121.300039 1740 HIGH ST,AUBURN,95603,CA,3,3,0,Residential,Tue May 20 00:00:00 EDT 2008,504000,38.891935,-121.08434 2733 DANA LOOP,EL DORADO HILLS,95762,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,541000,38.628459,-121.055078 9741 SADDLEBRED CT,WILTON,95693,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,560000,38.408841,-121.198039 7756 TIGERWOODS DR,SACRAMENTO,95829,CA,5,3,3984,Residential,Tue May 20 00:00:00 EDT 2008,572500,38.47643,-121.309243 5709 RIVER OAK WAY,CARMICHAEL,95608,CA,4,2,2222,Residential,Tue May 20 00:00:00 EDT 2008,582000,38.602461,-121.330979 2981 WRINGER DR,ROSEVILLE,95661,CA,4,3,3838,Residential,Tue May 20 00:00:00 EDT 2008,613401,38.735373,-121.227072 8616 ROCKPORTE CT,ROSEVILLE,95747,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,614000,38.742118,-121.359909 4128 HILL ST,FAIR OAKS,95628,CA,5,5,2846,Residential,Tue May 20 00:00:00 EDT 2008,680000,38.64167,-121.262099 1409 47TH ST,SACRAMENTO,95819,CA,5,2,2484,Residential,Tue May 20 00:00:00 EDT 2008,699000,38.563244,-121.446876 3935 EL MONTE DR,LOOMIS,95650,CA,4,4,1624,Residential,Tue May 20 00:00:00 EDT 2008,839000,38.813337,-121.133348 5840 WALERGA RD,SACRAMENTO,95842,CA,2,1,840,Condo,Mon May 19 00:00:00 EDT 2008,40000,38.673678,-121.357471 923 FULTON AVE,SACRAMENTO,95825,CA,1,1,484,Condo,Mon May 19 00:00:00 EDT 2008,48000,38.582279,-121.401482 261 REDONDO AVE,SACRAMENTO,95815,CA,3,1,970,Residential,Mon May 19 00:00:00 EDT 2008,61500,38.620685,-121.460539 4030 BROADWAY,SACRAMENTO,95817,CA,2,1,623,Residential,Mon May 19 00:00:00 EDT 2008,62050,38.546798,-121.460038 3660 22ND AVE,SACRAMENTO,95820,CA,2,1,932,Residential,Mon May 19 00:00:00 EDT 2008,65000,38.532718,-121.46747 3924 HIGH ST,SACRAMENTO,95838,CA,2,1,796,Residential,Mon May 19 00:00:00 EDT 2008,65000,38.638797,-121.435049 4734 14TH AVE,SACRAMENTO,95820,CA,2,1,834,Residential,Mon May 19 00:00:00 EDT 2008,68000,38.539447,-121.450858 4734 14TH AVE,SACRAMENTO,95820,CA,2,1,834,Residential,Mon May 19 00:00:00 EDT 2008,68000,38.539447,-121.450858 5050 RHODE ISLAND DR Unit 4,SACRAMENTO,95841,CA,2,1,924,Condo,Mon May 19 00:00:00 EDT 2008,77000,38.658739,-121.333561 4513 GREENHOLME DR,SACRAMENTO,95842,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,82732,38.669104,-121.359008 3845 ELM ST,SACRAMENTO,95838,CA,3,1,1250,Residential,Mon May 19 00:00:00 EDT 2008,84000,38.637337,-121.432835 3908 17TH AVE,SACRAMENTO,95820,CA,2,1,984,Residential,Mon May 19 00:00:00 EDT 2008,84675,38.53728,-121.463531 7109 CHANDLER DR,SACRAMENTO,95828,CA,3,1,1013,Residential,Mon May 19 00:00:00 EDT 2008,85000,38.497237,-121.424187 7541 SKELTON WAY,SACRAMENTO,95822,CA,3,1,1012,Residential,Mon May 19 00:00:00 EDT 2008,90000,38.484274,-121.488851 9058 MONTOYA ST,SACRAMENTO,95826,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,90000,38.559144,-121.368387 1016 CONGRESS AVE,SACRAMENTO,95838,CA,2,2,918,Residential,Mon May 19 00:00:00 EDT 2008,91000,38.630151,-121.442789 540 MORRISON AVE,SACRAMENTO,95838,CA,3,1,1082,Residential,Mon May 19 00:00:00 EDT 2008,95000,38.637704,-121.453946 5303 JERRETT WAY,SACRAMENTO,95842,CA,2,1,964,Residential,Mon May 19 00:00:00 EDT 2008,97500,38.663282,-121.359631 2820 DEL PASO BLVD,SACRAMENTO,95815,CA,4,2,1404,Multi-Family,Mon May 19 00:00:00 EDT 2008,100000,38.617718,-121.440089 3715 TALLYHO DR Unit 78HIGH,SACRAMENTO,95826,CA,1,1,625,Condo,Mon May 19 00:00:00 EDT 2008,100000,38.544627,-121.35796 6013 ROWAN WAY,CITRUS HEIGHTS,95621,CA,2,1,888,Residential,Mon May 19 00:00:00 EDT 2008,101000,38.675893,-121.2963 2987 PONDEROSA LN,SACRAMENTO,95815,CA,4,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,102750,38.622243,-121.457863 3732 LANKERSHIM WAY,NORTH HIGHLANDS,95660,CA,3,1,1331,Residential,Mon May 19 00:00:00 EDT 2008,112500,38.68972,-121.378399 2216 DUNLAP DR,SACRAMENTO,95821,CA,3,1,1014,Residential,Mon May 19 00:00:00 EDT 2008,113000,38.623738,-121.41305 3503 21ST AVE,SACRAMENTO,95820,CA,4,2,1448,Residential,Mon May 19 00:00:00 EDT 2008,114000,38.53361,-121.469308 523 EXCHANGE ST,SACRAMENTO,95838,CA,3,1,966,Residential,Mon May 19 00:00:00 EDT 2008,114000,38.659414,-121.45408 8101 PORT ROYALE WAY,SACRAMENTO,95823,CA,2,1,779,Residential,Mon May 19 00:00:00 EDT 2008,114750,38.463929,-121.438667 8020 WALERGA RD,ANTELOPE,95843,CA,2,2,836,Condo,Mon May 19 00:00:00 EDT 2008,115000,38.71607,-121.364468 167 VALLEY OAK DR,ROSEVILLE,95678,CA,2,2,1100,Condo,Mon May 19 00:00:00 EDT 2008,115000,38.732429,-121.288069 7876 BURLINGTON WAY,SACRAMENTO,95832,CA,3,1,1174,Residential,Mon May 19 00:00:00 EDT 2008,116100,38.470093,-121.468347 3726 JONKO AVE,NORTH HIGHLANDS,95660,CA,3,2,1207,Residential,Mon May 19 00:00:00 EDT 2008,119250,38.656131,-121.377265 7342 GIGI PL,SACRAMENTO,95828,CA,4,4,1995,Multi-Family,Mon May 19 00:00:00 EDT 2008,120000,38.490704,-121.410176 2610 PHYLLIS AVE,SACRAMENTO,95820,CA,2,1,804,Residential,Mon May 19 00:00:00 EDT 2008,120000,38.53105,-121.479574 4200 COMMERCE WAY Unit 711,SACRAMENTO,95834,CA,2,2,958,Condo,Mon May 19 00:00:00 EDT 2008,120000,38.647523,-121.523217 4621 COUNTRY SCENE WAY,SACRAMENTO,95823,CA,3,2,1366,Residential,Mon May 19 00:00:00 EDT 2008,120108,38.470187,-121.448149 5380 VILLAGE WOOD DR,SACRAMENTO,95823,CA,2,2,901,Residential,Mon May 19 00:00:00 EDT 2008,121500,38.454949,-121.440578 2621 EVERGREEN ST,SACRAMENTO,95815,CA,3,1,696,Residential,Mon May 19 00:00:00 EDT 2008,121725,38.613103,-121.444085 201 CARLO CT,GALT,95632,CA,3,2,1080,Residential,Mon May 19 00:00:00 EDT 2008,122000,38.24227,-121.31032 6743 21ST ST,SACRAMENTO,95822,CA,3,2,1104,Residential,Mon May 19 00:00:00 EDT 2008,123000,38.50372,-121.490657 3128 VIA GRANDE,SACRAMENTO,95825,CA,2,1,972,Residential,Mon May 19 00:00:00 EDT 2008,125000,38.598321,-121.39161 2847 BELGRADE WAY,SACRAMENTO,95833,CA,4,2,1390,Residential,Mon May 19 00:00:00 EDT 2008,125573,38.617173,-121.482541 7741 MILLDALE CIR,ELVERTA,95626,CA,4,2,1354,Residential,Mon May 19 00:00:00 EDT 2008,126714,38.705834,-121.43919 9013 CASALS ST,SACRAMENTO,95826,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,126960,38.557045,-121.37167 227 MAHAN CT Unit 1,ROSEVILLE,95678,CA,2,1,780,Condo,Mon May 19 00:00:00 EDT 2008,127000,38.749723,-121.27008 7349 FLETCHER FARM DR,SACRAMENTO,95828,CA,4,2,1587,Residential,Mon May 19 00:00:00 EDT 2008,127500,38.49069,-121.382619 7226 LARCHMONT DR,NORTH HIGHLANDS,95660,CA,3,2,1209,Residential,Mon May 19 00:00:00 EDT 2008,130000,38.699269,-121.376334 4114 35TH AVE,SACRAMENTO,95824,CA,2,1,1139,Residential,Mon May 19 00:00:00 EDT 2008,133105,38.520941,-121.459355 617 M ST,RIO LINDA,95673,CA,2,2,1690,Residential,Mon May 19 00:00:00 EDT 2008,136500,38.691104,-121.451832 7032 FAIR OAKS BLVD,CARMICHAEL,95608,CA,3,2,1245,Condo,Mon May 19 00:00:00 EDT 2008,139500,38.628563,-121.328297 2421 SANTINA WAY,ELVERTA,95626,CA,3,2,1416,Residential,Mon May 19 00:00:00 EDT 2008,140000,38.71865,-121.407763 2368 CRAIG AVE,SACRAMENTO,95832,CA,3,2,1300,Residential,Mon May 19 00:00:00 EDT 2008,140800,38.47807,-121.48114 2123 AMANDA WAY,SACRAMENTO,95822,CA,3,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,145000,38.484896,-121.486948 7620 DARLA WAY,SACRAMENTO,95828,CA,4,2,1590,Residential,Mon May 19 00:00:00 EDT 2008,147000,38.478502,-121.403517 8344 FIELDPOPPY CIR,SACRAMENTO,95828,CA,3,2,1407,Residential,Mon May 19 00:00:00 EDT 2008,149600,38.479083,-121.400702 3624 20TH AVE,SACRAMENTO,95820,CA,5,2,1516,Residential,Mon May 19 00:00:00 EDT 2008,150000,38.534508,-121.467907 10001 WOODCREEK OAKS BLVD Unit 1415,ROSEVILLE,95747,CA,2,2,0,Condo,Mon May 19 00:00:00 EDT 2008,150000,38.795529,-121.328819 2848 PROVO WAY,SACRAMENTO,95822,CA,3,2,1646,Residential,Mon May 19 00:00:00 EDT 2008,150000,38.489759,-121.474754 6045 EHRHARDT AVE,SACRAMENTO,95823,CA,3,2,1676,Residential,Mon May 19 00:00:00 EDT 2008,155000,38.457157,-121.433065 1223 LAMBERTON CIR,SACRAMENTO,95838,CA,3,2,1370,Residential,Mon May 19 00:00:00 EDT 2008,155435,38.646677,-121.437573 1223 LAMBERTON CIR,SACRAMENTO,95838,CA,3,2,1370,Residential,Mon May 19 00:00:00 EDT 2008,155500,38.646677,-121.437573 6000 BIRCHGLADE WAY,CITRUS HEIGHTS,95621,CA,4,2,1351,Residential,Mon May 19 00:00:00 EDT 2008,158000,38.70166,-121.323249 7204 THOMAS DR,NORTH HIGHLANDS,95660,CA,3,2,1152,Residential,Mon May 19 00:00:00 EDT 2008,158000,38.697898,-121.377687 8363 LANGTREE WAY,SACRAMENTO,95823,CA,3,2,1452,Residential,Mon May 19 00:00:00 EDT 2008,160000,38.45356,-121.435959 1675 VERNON ST Unit 8,ROSEVILLE,95678,CA,2,1,990,Residential,Mon May 19 00:00:00 EDT 2008,160000,38.734136,-121.299639 6632 IBEX WOODS CT,CITRUS HEIGHTS,95621,CA,2,2,1162,Residential,Mon May 19 00:00:00 EDT 2008,164000,38.720868,-121.309855 117 EVCAR WAY,RIO LINDA,95673,CA,3,2,1182,Residential,Mon May 19 00:00:00 EDT 2008,164000,38.687659,-121.4633 6485 LAGUNA MIRAGE LN,ELK GROVE,95758,CA,2,2,1112,Residential,Mon May 19 00:00:00 EDT 2008,165000,38.42465,-121.430137 746 MOOSE CREEK WAY,GALT,95632,CA,3,2,1100,Residential,Mon May 19 00:00:00 EDT 2008,167000,38.283085,-121.302071 8306 CURLEW CT,CITRUS HEIGHTS,95621,CA,4,2,1280,Residential,Mon May 19 00:00:00 EDT 2008,167293,38.715781,-121.298519 8306 CURLEW CT,CITRUS HEIGHTS,95621,CA,4,2,1280,Residential,Mon May 19 00:00:00 EDT 2008,167293,38.715781,-121.298519 5217 ARGO WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Mon May 19 00:00:00 EDT 2008,168000,38.52774,-121.433669 7108 HEATHER TREE DR,SACRAMENTO,95842,CA,3,2,1159,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.695677,-121.36022 2956 DAVENPORT WAY,SACRAMENTO,95833,CA,4,2,1917,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.620687,-121.482619 10062 LINCOLN VILLAGE DR,SACRAMENTO,95827,CA,3,2,1520,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.564,-121.320023 332 PALIN AVE,GALT,95632,CA,3,2,1204,Residential,Mon May 19 00:00:00 EDT 2008,174000,38.260467,-121.302636 4649 FREEWAY CIR,SACRAMENTO,95841,CA,3,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,178000,38.658734,-121.357196 8593 DERLIN WAY,SACRAMENTO,95823,CA,3,2,1436,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.447585,-121.426627 9273 PREMIER WAY,SACRAMENTO,95826,CA,3,2,1451,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.55992,-121.352539 8032 DUSENBERG CT,SACRAMENTO,95828,CA,4,2,1638,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.466499,-121.381119 7110 STELLA LN Unit 15,CARMICHAEL,95608,CA,2,2,1000,Condo,Mon May 19 00:00:00 EDT 2008,182000,38.637396,-121.300055 1786 PIEDMONT WAY,ROSEVILLE,95661,CA,3,1,1152,Residential,Mon May 19 00:00:00 EDT 2008,188325,38.72748,-121.256537 1347 HIDALGO CIR,ROSEVILLE,95747,CA,3,2,1154,Residential,Mon May 19 00:00:00 EDT 2008,191500,38.747878,-121.311279 212 CAPPUCINO WAY,SACRAMENTO,95838,CA,3,2,1353,Residential,Mon May 19 00:00:00 EDT 2008,192000,38.657811,-121.465327 5938 WOODBRIAR WAY,CITRUS HEIGHTS,95621,CA,3,2,1329,Residential,Mon May 19 00:00:00 EDT 2008,192700,38.706152,-121.325399 3801 WILDROSE WAY,SACRAMENTO,95826,CA,3,1,1356,Residential,Mon May 19 00:00:00 EDT 2008,195000,38.544368,-121.369979 508 SAMUEL WAY,SACRAMENTO,95838,CA,3,2,1505,Residential,Mon May 19 00:00:00 EDT 2008,197654,38.645689,-121.452766 6128 CARL SANDBURG CIR,SACRAMENTO,95842,CA,3,1,1009,Residential,Mon May 19 00:00:00 EDT 2008,198000,38.681541,-121.355616 1 KENNELFORD CIR,SACRAMENTO,95823,CA,3,2,1144,Residential,Mon May 19 00:00:00 EDT 2008,200345,38.46452,-121.427606 909 SINGINGWOOD RD,SACRAMENTO,95864,CA,2,1,930,Residential,Mon May 19 00:00:00 EDT 2008,203000,38.581471,-121.38839 6671 FOXWOOD CT,SACRAMENTO,95841,CA,4,2,1766,Residential,Mon May 19 00:00:00 EDT 2008,207000,38.687943,-121.328883 8165 AYN RAND CT,SACRAMENTO,95828,CA,4,3,1940,Residential,Mon May 19 00:00:00 EDT 2008,208000,38.468639,-121.403265 9474 VILLAGE TREE DR,ELK GROVE,95758,CA,4,2,1776,Residential,Mon May 19 00:00:00 EDT 2008,210000,38.413947,-121.408276 7213 CALVIN DR,CITRUS HEIGHTS,95621,CA,3,1,1258,Residential,Mon May 19 00:00:00 EDT 2008,212000,38.698154,-121.298375 8167 DERBY PARK CT,SACRAMENTO,95828,CA,4,2,1872,Residential,Mon May 19 00:00:00 EDT 2008,213675,38.460492,-121.373379 6344 LAGUNA MIRAGE LN,ELK GROVE,95758,CA,2,2,1112,Residential,Mon May 19 00:00:00 EDT 2008,213697,38.423963,-121.428875 2945 RED HAWK WAY,SACRAMENTO,95833,CA,4,2,1856,Residential,Mon May 19 00:00:00 EDT 2008,215000,38.619675,-121.496903 3228 I ST,SACRAMENTO,95816,CA,4,3,1939,Residential,Mon May 19 00:00:00 EDT 2008,215000,38.573844,-121.462839 308 ATKINSON ST,ROSEVILLE,95678,CA,3,1,998,Residential,Mon May 19 00:00:00 EDT 2008,215100,38.746794,-121.29971 624 HOVEY WAY,ROSEVILLE,95678,CA,3,2,1758,Residential,Mon May 19 00:00:00 EDT 2008,217500,38.756149,-121.306479 110 COPPER LEAF WAY,SACRAMENTO,95838,CA,3,2,2142,Residential,Mon May 19 00:00:00 EDT 2008,218000,38.658466,-121.460661 7535 ALMA VISTA WAY,SACRAMENTO,95831,CA,2,1,950,Residential,Mon May 19 00:00:00 EDT 2008,220000,38.48403,-121.507641 7423 WILSALL CT,ELK GROVE,95758,CA,4,3,1739,Residential,Mon May 19 00:00:00 EDT 2008,221000,38.417026,-121.416821 8629 VIA ALTA WAY,ELK GROVE,95624,CA,3,2,1516,Residential,Mon May 19 00:00:00 EDT 2008,222900,38.398245,-121.380615 3318 DAVIDSON DR,ANTELOPE,95843,CA,3,1,988,Residential,Mon May 19 00:00:00 EDT 2008,223139,38.705753,-121.388917 913 COBDEN CT,GALT,95632,CA,4,2,1555,Residential,Mon May 19 00:00:00 EDT 2008,225500,38.282001,-121.295902 4419 79TH ST,SACRAMENTO,95820,CA,3,2,1212,Residential,Mon May 19 00:00:00 EDT 2008,228327,38.534827,-121.412545 3012 SPOONWOOD WAY,SACRAMENTO,95833,CA,4,2,1871,Residential,Mon May 19 00:00:00 EDT 2008,230000,38.62478,-121.523474 8728 CRYSTAL RIVER WAY,SACRAMENTO,95828,CA,3,2,1302,Residential,Mon May 19 00:00:00 EDT 2008,230000,38.47547,-121.380055 4709 AMBER LN Unit 1,SACRAMENTO,95841,CA,2,1,756,Condo,Mon May 19 00:00:00 EDT 2008,230522,38.657789,-121.354994 4508 OLD DAIRY DR,ANTELOPE,95843,CA,4,3,2026,Residential,Mon May 19 00:00:00 EDT 2008,231200,38.72286,-121.358939 312 RIVER ISLE WAY,SACRAMENTO,95831,CA,3,2,1375,Residential,Mon May 19 00:00:00 EDT 2008,232000,38.49026,-121.550527 301 OLIVADI WAY,SACRAMENTO,95834,CA,2,2,1250,Condo,Mon May 19 00:00:00 EDT 2008,232500,38.644406,-121.549049 5636 25TH ST,SACRAMENTO,95822,CA,3,1,1058,Residential,Mon May 19 00:00:00 EDT 2008,233641,38.523828,-121.481139 8721 SPRUCE RIDGE WAY,ANTELOPE,95843,CA,3,2,1187,Residential,Mon May 19 00:00:00 EDT 2008,234000,38.727657,-121.391028 7461 WINDBRIDGE DR,SACRAMENTO,95831,CA,2,2,1324,Residential,Mon May 19 00:00:00 EDT 2008,234500,38.48797,-121.530229 8101 LEMON COVE CT,SACRAMENTO,95828,CA,4,3,1936,Residential,Mon May 19 00:00:00 EDT 2008,235000,38.462981,-121.408288 10949 SCOTSMAN WAY,RANCHO CORDOVA,95670,CA,5,4,2382,Multi-Family,Mon May 19 00:00:00 EDT 2008,236000,38.603686,-121.277844 617 WILLOW CREEK DR,FOLSOM,95630,CA,3,2,1427,Residential,Mon May 19 00:00:00 EDT 2008,236073,38.679626,-121.142609 3301 PARK DR Unit 1914,SACRAMENTO,95835,CA,3,2,1678,Condo,Mon May 19 00:00:00 EDT 2008,238000,38.665296,-121.531993 709 CIMMARON CT,GALT,95632,CA,4,2,1798,Residential,Mon May 19 00:00:00 EDT 2008,238861,38.277177,-121.303747 3305 RIO ROCA CT,ANTELOPE,95843,CA,4,3,2652,Residential,Mon May 19 00:00:00 EDT 2008,239700,38.725079,-121.387698 9080 BEDROCK CT,SACRAMENTO,95829,CA,4,2,1816,Residential,Mon May 19 00:00:00 EDT 2008,240000,38.456939,-121.362965 100 TOURMALINE CIR,SACRAMENTO,95834,CA,5,3,3076,Residential,Mon May 19 00:00:00 EDT 2008,240000,38.63437,-121.510779 6411 RED BIRCH WAY,ELK GROVE,95758,CA,4,2,1844,Residential,Mon May 19 00:00:00 EDT 2008,241000,38.43461,-121.429316 4867 LAGUNA DR,SACRAMENTO,95823,CA,3,2,1306,Residential,Mon May 19 00:00:00 EDT 2008,245000,38.46179,-121.445371 3662 RIVER DR,SACRAMENTO,95833,CA,4,3,2447,Residential,Mon May 19 00:00:00 EDT 2008,246000,38.604969,-121.54255 6943 WOLFGRAM WAY,SACRAMENTO,95828,CA,4,2,1176,Residential,Mon May 19 00:00:00 EDT 2008,247234,38.489215,-121.419546 77 RINETTI WAY,RIO LINDA,95673,CA,4,2,1182,Residential,Mon May 19 00:00:00 EDT 2008,247480,38.687021,-121.463151 1316 I ST,RIO LINDA,95673,CA,3,1,1160,Residential,Mon May 19 00:00:00 EDT 2008,249862,38.683674,-121.435204 2130 CATHERWOOD WAY,SACRAMENTO,95835,CA,3,2,1424,Residential,Mon May 19 00:00:00 EDT 2008,251000,38.675506,-121.510987 8304 JUGLANS DR,ORANGEVALE,95662,CA,4,2,1574,Residential,Mon May 19 00:00:00 EDT 2008,252155,38.691829,-121.249033 5308 MARBURY WAY,ANTELOPE,95843,CA,3,2,1830,Residential,Mon May 19 00:00:00 EDT 2008,254172,38.710221,-121.341707 9182 LAKEMONT DR,ELK GROVE,95624,CA,4,2,1724,Residential,Mon May 19 00:00:00 EDT 2008,258000,38.451353,-121.358776 2231 COUNTRY VILLA CT,AUBURN,95603,CA,2,2,1255,Condo,Mon May 19 00:00:00 EDT 2008,260000,38.931671,-121.097862 8491 CRYSTAL WALK CIR,ELK GROVE,95758,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.416916,-121.407554 361 MAHONIA CIR,SACRAMENTO,95835,CA,4,3,2175,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.676172,-121.509761 3427 LA CADENA WAY,SACRAMENTO,95835,CA,4,2,1904,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.681194,-121.537351 955 BIG SUR CT,EL DORADO HILLS,95762,CA,4,2,1808,Residential,Mon May 19 00:00:00 EDT 2008,262500,38.664347,-121.076529 11826 DIONYSUS WAY,RANCHO CORDOVA,95742,CA,4,2,2711,Residential,Mon May 19 00:00:00 EDT 2008,266000,38.551046,-121.239411 5847 DEL CAMPO LN,CARMICHAEL,95608,CA,3,1,1713,Residential,Mon May 19 00:00:00 EDT 2008,266000,38.671995,-121.324339 5635 FOXVIEW WAY,ELK GROVE,95757,CA,3,2,1457,Residential,Mon May 19 00:00:00 EDT 2008,270000,38.395256,-121.438249 10372 VIA CINTA CT,ELK GROVE,95757,CA,4,3,2724,Residential,Mon May 19 00:00:00 EDT 2008,274425,38.380089,-121.428186 6286 LONETREE BLVD,ROCKLIN,95765,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,274500,38.805036,-121.293608 7744 SOUTHBREEZE DR,SACRAMENTO,95828,CA,3,2,1468,Residential,Mon May 19 00:00:00 EDT 2008,275336,38.476932,-121.378349 2242 ABLE WAY,SACRAMENTO,95835,CA,4,3,2550,Residential,Mon May 19 00:00:00 EDT 2008,277980,38.666074,-121.509743 1042 STARBROOK DR,GALT,95632,CA,4,2,1928,Residential,Mon May 19 00:00:00 EDT 2008,280000,38.285611,-121.293063 1219 G ST,SACRAMENTO,95814,CA,3,3,1922,Residential,Mon May 19 00:00:00 EDT 2008,284686,38.582818,-121.489096 6220 OPUS CT,CITRUS HEIGHTS,95621,CA,3,2,1343,Residential,Mon May 19 00:00:00 EDT 2008,284893,38.715853,-121.317095 5419 HAVENHURST CIR,ROCKLIN,95677,CA,3,2,1510,Residential,Mon May 19 00:00:00 EDT 2008,285000,38.786746,-121.209957 220 OLD AIRPORT RD,AUBURN,95603,CA,2,2,960,Multi-Family,Mon May 19 00:00:00 EDT 2008,285000,38.939802,-121.054575 4622 MEYER WAY,CARMICHAEL,95608,CA,4,2,1559,Residential,Mon May 19 00:00:00 EDT 2008,285000,38.64913,-121.310667 4885 SUMMIT VIEW DR,EL DORADO,95623,CA,3,2,1624,Residential,Mon May 19 00:00:00 EDT 2008,289000,38.673285,-120.879176 26 JEANROSS CT,SACRAMENTO,95832,CA,5,3,2992,Residential,Mon May 19 00:00:00 EDT 2008,295000,38.473162,-121.491085 4800 MAPLEPLAIN AVE,ELK GROVE,95758,CA,4,2,2109,Residential,Mon May 19 00:00:00 EDT 2008,296000,38.432848,-121.449237 10629 BASIE WAY,RANCHO CORDOVA,95670,CA,4,2,1524,Residential,Mon May 19 00:00:00 EDT 2008,296056,38.579,-121.292627 8612 WILLOW GROVE WAY,SACRAMENTO,95828,CA,3,2,1248,Residential,Mon May 19 00:00:00 EDT 2008,297359,38.464994,-121.386962 62 DE FER CIR,SACRAMENTO,95823,CA,4,2,1876,Residential,Mon May 19 00:00:00 EDT 2008,299940,38.49254,-121.463316 2513 OLD KENMARE RD,LINCOLN,95648,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,304000,38.847396,-121.259586 3253 ABOTO WAY,RANCHO CORDOVA,95670,CA,4,3,1851,Residential,Mon May 19 00:00:00 EDT 2008,305000,38.57727,-121.285591 3072 VILLAGE PLAZA DR,ROSEVILLE,95747,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,307000,38.773094,-121.365905 251 CHANGO CIR,SACRAMENTO,95835,CA,4,2,2218,Residential,Mon May 19 00:00:00 EDT 2008,311328,38.68237,-121.539147 8205 WEYBURN CT,SACRAMENTO,95828,CA,3,2,1394,Residential,Mon May 19 00:00:00 EDT 2008,313138,38.47316,-121.403893 8788 LA MARGARITA WAY,SACRAMENTO,95828,CA,3,2,1410,Residential,Mon May 19 00:00:00 EDT 2008,316630,38.468185,-121.375694 5912 DEEPDALE WAY,ELK GROVE,95758,CA,5,3,3468,Residential,Mon May 19 00:00:00 EDT 2008,320000,38.439565,-121.436606 4712 PISMO BEACH DR,ANTELOPE,95843,CA,5,3,2346,Residential,Mon May 19 00:00:00 EDT 2008,320000,38.707705,-121.354153 4741 PACIFIC PARK DR,ANTELOPE,95843,CA,5,3,2347,Residential,Mon May 19 00:00:00 EDT 2008,325000,38.709299,-121.353056 310 GROTH CIR,SACRAMENTO,95834,CA,4,2,1659,Residential,Mon May 19 00:00:00 EDT 2008,328578,38.638764,-121.531827 6121 WILD FOX CT,ELK GROVE,95757,CA,3,3,2442,Residential,Mon May 19 00:00:00 EDT 2008,331000,38.406758,-121.431669 12241 CANYONLANDS DR,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,331500,38.557293,-121.217611 29 COOL FOUNTAIN CT,SACRAMENTO,95833,CA,4,2,2155,Residential,Mon May 19 00:00:00 EDT 2008,340000,38.606906,-121.54132 907 RIO ROBLES AVE,SACRAMENTO,95838,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,344755,38.664765,-121.445006 8909 BILLFISH WAY,SACRAMENTO,95828,CA,3,2,1810,Residential,Mon May 19 00:00:00 EDT 2008,345746,38.475433,-121.372584 6232 GUS WAY,ELK GROVE,95757,CA,4,2,2789,Residential,Mon May 19 00:00:00 EDT 2008,351000,38.388129,-121.43117 200 OAKWILDE ST,GALT,95632,CA,4,2,1606,Residential,Mon May 19 00:00:00 EDT 2008,353767,38.2535,-121.31812 1033 PARK STREAM DR,GALT,95632,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,355000,38.287785,-121.289903 200 ALLAIRE CIR,SACRAMENTO,95835,CA,4,2,2166,Residential,Mon May 19 00:00:00 EDT 2008,356035,38.68318,-121.53484 1322 SUTTER WALK,SACRAMENTO,95816,CA,0,0,0,Condo,Mon May 19 00:00:00 EDT 2008,360000,38.53805,-121.5047 5479 NICKMAN WAY,SACRAMENTO,95835,CA,4,2,1871,Residential,Mon May 19 00:00:00 EDT 2008,360552,38.672966,-121.502748 2103 BURBERRY WAY,SACRAMENTO,95835,CA,3,2,1800,Residential,Mon May 19 00:00:00 EDT 2008,362305,38.67342,-121.508542 2450 SAN JOSE WAY,SACRAMENTO,95817,CA,3,1,1683,Residential,Mon May 19 00:00:00 EDT 2008,365000,38.553596,-121.459483 7641 ROSEHALL DR,ROSEVILLE,95678,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,367554,38.791617,-121.286147 1336 LAYSAN TEAL DR,ROSEVILLE,95747,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,368500,38.796121,-121.319963 2802 BLACK OAK DR,ROCKLIN,95765,CA,2,2,1596,Residential,Mon May 19 00:00:00 EDT 2008,370000,38.837006,-121.232024 2113 FALL TRAIL CT,PLACERVILLE,95667,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,371086,38.733155,-120.748039 10112 LAMBEAU CT,ELK GROVE,95757,CA,3,2,1179,Residential,Mon May 19 00:00:00 EDT 2008,378000,38.390328,-121.448022 6313 CASTRO VERDE WAY,ELK GROVE,95757,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,383000,38.381102,-121.42901 3622 CURTIS DR,SACRAMENTO,95818,CA,3,1,1639,Residential,Mon May 19 00:00:00 EDT 2008,388000,38.541735,-121.480098 11817 OPAL RIDGE WAY,RANCHO CORDOVA,95742,CA,5,3,3281,Residential,Mon May 19 00:00:00 EDT 2008,395100,38.551083,-121.237476 170 LAGOMARSINO WAY,SACRAMENTO,95819,CA,3,2,1697,Residential,Mon May 19 00:00:00 EDT 2008,400000,38.574894,-121.435806 2743 DEAKIN PL,EL DORADO HILLS,95762,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,400000,38.69288,-121.073551 3361 ALDER CANYON WAY,ANTELOPE,95843,CA,4,3,2085,Residential,Mon May 19 00:00:00 EDT 2008,408431,38.727649,-121.385656 2148 RANCH VIEW DR,ROCKLIN,95765,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,413000,38.837455,-121.289337 398 LINDLEY DR,SACRAMENTO,95815,CA,4,2,1744,Multi-Family,Mon May 19 00:00:00 EDT 2008,416767,38.622359,-121.457582 3013 BRIDLEWOOD DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Mon May 19 00:00:00 EDT 2008,420000,38.675519,-121.015862 169 BAURER CIR,FOLSOM,95630,CA,4,3,1939,Residential,Mon May 19 00:00:00 EDT 2008,423000,38.66695,-121.120729 2809 LOON CT,CAMERON PARK,95682,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,423000,38.687072,-121.004729 1315 KONDOS AVE,SACRAMENTO,95814,CA,2,3,1788,Residential,Mon May 19 00:00:00 EDT 2008,427500,38.571943,-121.492106 4966 CHARTER RD,ROCKLIN,95765,CA,3,2,1691,Residential,Mon May 19 00:00:00 EDT 2008,430922,38.82553,-121.254698 9516 LAGUNA LAKE WAY,ELK GROVE,95758,CA,4,2,2002,Residential,Mon May 19 00:00:00 EDT 2008,445000,38.411258,-121.431348 5201 BLOSSOM RANCH DR,ELK GROVE,95757,CA,4,4,4303,Residential,Mon May 19 00:00:00 EDT 2008,450000,38.399436,-121.444041 3027 PALMATE WAY,SACRAMENTO,95834,CA,5,3,4246,Residential,Mon May 19 00:00:00 EDT 2008,452000,38.628955,-121.529269 500 WINCHESTER CT,ROSEVILLE,95661,CA,3,2,2274,Residential,Mon May 19 00:00:00 EDT 2008,470000,38.73988,-121.248929 5746 GELSTON WAY,EL DORADO HILLS,95762,CA,4,3,0,Residential,Mon May 19 00:00:00 EDT 2008,471000,38.677015,-121.034083 6935 ELM TREE LN,ORANGEVALE,95662,CA,4,4,3056,Residential,Mon May 19 00:00:00 EDT 2008,475000,38.693041,-121.23294 9605 GOLF COURSE LN,ELK GROVE,95758,CA,3,3,2503,Residential,Mon May 19 00:00:00 EDT 2008,484500,38.409689,-121.446059 719 BAYWOOD CT,EL DORADO HILLS,95762,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,487500,38.647598,-121.077801 5954 TANUS CIR,ROCKLIN,95677,CA,3,3,0,Residential,Mon May 19 00:00:00 EDT 2008,488750,38.777585,-121.2036 100 CHELSEA CT,FOLSOM,95630,CA,3,2,1905,Residential,Mon May 19 00:00:00 EDT 2008,500000,38.69435,-121.177259 1500 ORANGE HILL LN,PENRYN,95663,CA,3,2,1320,Residential,Mon May 19 00:00:00 EDT 2008,506688,38.862708,-121.162092 408 KIRKWOOD CT,LINCOLN,95648,CA,2,2,0,Residential,Mon May 19 00:00:00 EDT 2008,512000,38.861615,-121.26869 1732 TUSCAN GROVE CIR,ROSEVILLE,95747,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,520000,38.796683,-121.342555 2049 EMPIRE MINE CIR,GOLD RIVER,95670,CA,4,2,3037,Residential,Mon May 19 00:00:00 EDT 2008,528000,38.629299,-121.249021 9360 MAGOS RD,WILTON,95693,CA,5,2,3741,Residential,Mon May 19 00:00:00 EDT 2008,579093,38.416809,-121.240628 104 CATLIN CT,FOLSOM,95630,CA,4,3,2660,Residential,Mon May 19 00:00:00 EDT 2008,636000,38.684459,-121.145935 4734 GIBBONS DR,CARMICHAEL,95608,CA,4,3,3357,Residential,Mon May 19 00:00:00 EDT 2008,668365,38.63558,-121.353639 4629 DORCHESTER LN,GRANITE BAY,95746,CA,5,3,2896,Residential,Mon May 19 00:00:00 EDT 2008,676200,38.723545,-121.216025 2400 COUNTRYSIDE DR,PLACERVILLE,95667,CA,3,2,2025,Residential,Mon May 19 00:00:00 EDT 2008,677048,38.737452,-120.910963 12901 FURLONG DR,WILTON,95693,CA,5,3,3788,Residential,Mon May 19 00:00:00 EDT 2008,691659,38.413535,-121.188211 6222 CALLE MONTALVO CIR,GRANITE BAY,95746,CA,5,3,3670,Residential,Mon May 19 00:00:00 EDT 2008,760000,38.779435,-121.146676 20 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885327,-121.289412 24 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885132,-121.289405 28 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884936,-121.289397 32 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884741,-121.28939 36 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884599,-121.289406 40 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884535,-121.289619 44 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88459,-121.289835 48 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884667,-121.289896 52 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88478,-121.289911 68 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885236,-121.289928 72 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88535,-121.289926 76 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885464,-121.289922 80 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885578,-121.289919 84 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885692,-121.289915 88 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885806,-121.289911 92 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88592,-121.289908 96 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886024,-121.289859 100 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886091,-121.289744 434 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88653,-121.289406 3 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884692,-121.290288 11 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884879,-121.290257 19 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885017,-121.290262 27 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885173,-121.29027 35 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885328,-121.290275 43 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885483,-121.290277 51 E ST,LINCOLN,95648,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885638,-121.290279 59 E ST,LINCOLN,95648,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885794,-121.290281 75 E ST,LINCOLN,95648,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886104,-121.290285 63 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885093,-121.289932 398 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88653,-121.288952 386 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886528,-121.288869 374 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886525,-121.288787 116 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289586 108 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289646 100 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289706 55 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884865,-121.289922 51 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884752,-121.289907 47 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884638,-121.289893 43 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884568,-121.289784 39 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884546,-121.289562 35 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884645,-121.289397 31 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88479,-121.289392 27 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884985,-121.289399 23 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885181,-121.289406 19 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885376,-121.289414 15 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885571,-121.289421 7 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885962,-121.289436 7 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885962,-121.289436 3 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886093,-121.289584 8208 WOODYARD WAY,CITRUS HEIGHTS,95621,CA,3,2,1166,Residential,Fri May 16 00:00:00 EDT 2008,30000,38.715322,-121.314787 113 RINETTI WAY,RIO LINDA,95673,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,30000,38.687172,-121.463933 15 LOORZ CT,SACRAMENTO,95823,CA,2,1,838,Residential,Fri May 16 00:00:00 EDT 2008,55422,38.471646,-121.435158 5805 DOTMAR WAY,NORTH HIGHLANDS,95660,CA,2,1,904,Residential,Fri May 16 00:00:00 EDT 2008,63000,38.672642,-121.380343 2332 CAMBRIDGE ST,SACRAMENTO,95815,CA,2,1,1032,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.608085,-121.449651 3812 BELDEN ST,SACRAMENTO,95838,CA,2,1,904,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.636833,-121.44164 3348 40TH ST,SACRAMENTO,95817,CA,2,1,1080,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.544162,-121.460652 127 QUASAR CIR,SACRAMENTO,95822,CA,2,2,990,Residential,Fri May 16 00:00:00 EDT 2008,66500,38.493504,-121.475304 3812 CYPRESS ST,SACRAMENTO,95838,CA,2,1,900,Residential,Fri May 16 00:00:00 EDT 2008,71000,38.636877,-121.444948 5821 64TH ST,SACRAMENTO,95824,CA,2,1,861,Residential,Fri May 16 00:00:00 EDT 2008,75000,38.521202,-121.428146 8248 CENTER PKWY,SACRAMENTO,95823,CA,2,1,906,Condo,Fri May 16 00:00:00 EDT 2008,77000,38.459002,-121.428794 1171 SONOMA AVE,SACRAMENTO,95815,CA,2,1,1011,Residential,Fri May 16 00:00:00 EDT 2008,85000,38.6238,-121.439872 4250 ARDWELL WAY,SACRAMENTO,95823,CA,3,2,1089,Residential,Fri May 16 00:00:00 EDT 2008,95625,38.466938,-121.455631 3104 CLAY ST,SACRAMENTO,95815,CA,2,1,832,Residential,Fri May 16 00:00:00 EDT 2008,96140,38.62391,-121.439208 6063 LAND PARK DR,SACRAMENTO,95822,CA,2,1,800,Condo,Fri May 16 00:00:00 EDT 2008,104250,38.517029,-121.513809 4738 OAKHOLLOW DR,SACRAMENTO,95842,CA,4,2,1292,Residential,Fri May 16 00:00:00 EDT 2008,105000,38.679598,-121.356035 1401 STERLING ST,SACRAMENTO,95822,CA,2,1,810,Residential,Fri May 16 00:00:00 EDT 2008,108000,38.520319,-121.504727 3715 DIDCOT CIR,SACRAMENTO,95838,CA,4,2,1064,Residential,Fri May 16 00:00:00 EDT 2008,109000,38.635232,-121.460098 2426 RASHAWN DR,RANCHO CORDOVA,95670,CA,2,1,911,Residential,Fri May 16 00:00:00 EDT 2008,115000,38.610852,-121.273278 4800 WESTLAKE PKWY Unit 410,SACRAMENTO,95835,CA,1,1,846,Condo,Fri May 16 00:00:00 EDT 2008,115000,38.658812,-121.542345 3409 VIRGO ST,SACRAMENTO,95827,CA,3,2,1320,Residential,Fri May 16 00:00:00 EDT 2008,115500,38.563402,-121.327747 1110 PINEDALE AVE,SACRAMENTO,95838,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,115620,38.660173,-121.440216 2361 LA LOMA DR,RANCHO CORDOVA,95670,CA,3,2,1115,Residential,Fri May 16 00:00:00 EDT 2008,116000,38.59368,-121.316054 1455 64TH AVE,SACRAMENTO,95822,CA,3,2,1169,Residential,Fri May 16 00:00:00 EDT 2008,122000,38.492177,-121.503392 7328 SPRINGMAN ST,SACRAMENTO,95822,CA,3,2,1164,Residential,Fri May 16 00:00:00 EDT 2008,122500,38.491991,-121.477636 119 SAINT MARIE CIR,SACRAMENTO,95823,CA,4,2,1341,Residential,Fri May 16 00:00:00 EDT 2008,123000,38.481454,-121.446644 12 COSTA BRASE CT,SACRAMENTO,95838,CA,3,2,1219,Residential,Fri May 16 00:00:00 EDT 2008,124000,38.655554,-121.464275 6813 SCOTER WAY,SACRAMENTO,95842,CA,4,2,1127,Residential,Fri May 16 00:00:00 EDT 2008,124000,38.69043,-121.361035 6548 GRAYLOCK LN,NORTH HIGHLANDS,95660,CA,3,2,1272,Residential,Fri May 16 00:00:00 EDT 2008,124413,38.686061,-121.369949 1630 GLIDDEN AVE,SACRAMENTO,95822,CA,4,2,1253,Residential,Fri May 16 00:00:00 EDT 2008,125000,38.482717,-121.499683 7825 DALEWOODS WAY,SACRAMENTO,95828,CA,3,2,1120,Residential,Fri May 16 00:00:00 EDT 2008,130000,38.477297,-121.411513 4073 TRESLER AVE,NORTH HIGHLANDS,95660,CA,2,2,1118,Residential,Fri May 16 00:00:00 EDT 2008,131750,38.659016,-121.370457 4288 DYMIC WAY,SACRAMENTO,95838,CA,4,3,1890,Residential,Fri May 16 00:00:00 EDT 2008,137721,38.646541,-121.441139 1158 SAN IGNACIO WAY,SACRAMENTO,95833,CA,3,2,1260,Residential,Fri May 16 00:00:00 EDT 2008,137760,38.623045,-121.486279 4904 J PKWY,SACRAMENTO,95823,CA,3,2,1400,Residential,Fri May 16 00:00:00 EDT 2008,138000,38.487297,-121.44295 2931 HOWE AVE,SACRAMENTO,95821,CA,3,1,1264,Residential,Fri May 16 00:00:00 EDT 2008,140000,38.619012,-121.415329 5531 JANSEN DR,SACRAMENTO,95824,CA,3,1,1060,Residential,Fri May 16 00:00:00 EDT 2008,145000,38.522015,-121.438713 7836 ORCHARD WOODS CIR,SACRAMENTO,95828,CA,2,2,1132,Residential,Fri May 16 00:00:00 EDT 2008,145000,38.47955,-121.410867 4055 DEERBROOK DR,SACRAMENTO,95823,CA,3,2,1466,Residential,Fri May 16 00:00:00 EDT 2008,150000,38.472117,-121.459589 9937 BURLINE ST,SACRAMENTO,95827,CA,3,2,1092,Residential,Fri May 16 00:00:00 EDT 2008,150000,38.559641,-121.32316 6948 MIRADOR WAY,SACRAMENTO,95828,CA,4,2,1628,Residential,Fri May 16 00:00:00 EDT 2008,151000,38.493484,-121.42035 4909 RUGER CT,SACRAMENTO,95842,CA,3,2,960,Residential,Fri May 16 00:00:00 EDT 2008,155000,38.68747,-121.349234 7204 KERSTEN ST,CITRUS HEIGHTS,95621,CA,3,2,1075,Residential,Fri May 16 00:00:00 EDT 2008,155800,38.695863,-121.300814 3150 ROSEMONT DR,SACRAMENTO,95826,CA,3,2,1428,Residential,Fri May 16 00:00:00 EDT 2008,156142,38.554927,-121.35521 8200 STEINBECK WAY,SACRAMENTO,95828,CA,4,2,1358,Residential,Fri May 16 00:00:00 EDT 2008,158000,38.474854,-121.404726 8198 STEVENSON AVE,SACRAMENTO,95828,CA,6,4,2475,Multi-Family,Fri May 16 00:00:00 EDT 2008,159900,38.465271,-121.40426 6824 OLIVE TREE WAY,CITRUS HEIGHTS,95610,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,160000,38.689239,-121.267737 3536 SUN MAIDEN WAY,ANTELOPE,95843,CA,3,2,1711,Residential,Fri May 16 00:00:00 EDT 2008,161500,38.70968,-121.382328 4517 OLYMPIAD WAY,SACRAMENTO,95826,CA,4,2,1483,Residential,Fri May 16 00:00:00 EDT 2008,161600,38.536751,-121.359154 925 COBDEN CT,GALT,95632,CA,3,2,1140,Residential,Fri May 16 00:00:00 EDT 2008,162000,38.282047,-121.295812 8225 SCOTTSDALE DR,SACRAMENTO,95828,CA,4,2,1549,Residential,Fri May 16 00:00:00 EDT 2008,165000,38.487864,-121.402476 8758 LEMAS RD,SACRAMENTO,95828,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,165000,38.467487,-121.377055 6121 ALPINESPRING WAY,ELK GROVE,95758,CA,3,2,1240,Residential,Fri May 16 00:00:00 EDT 2008,167293,38.434075,-121.432623 5937 YORK GLEN WAY,SACRAMENTO,95842,CA,5,2,1712,Residential,Fri May 16 00:00:00 EDT 2008,168000,38.677003,-121.354454 6417 SUNNYFIELD WAY,SACRAMENTO,95823,CA,4,2,1580,Residential,Fri May 16 00:00:00 EDT 2008,168000,38.449153,-121.428272 4008 GREY LIVERY WAY,ANTELOPE,95843,CA,3,2,1669,Residential,Fri May 16 00:00:00 EDT 2008,168750,38.71846,-121.370862 8920 ROSETTA CIR,SACRAMENTO,95826,CA,3,1,1029,Residential,Fri May 16 00:00:00 EDT 2008,168750,38.544374,-121.370874 8300 LICHEN DR,CITRUS HEIGHTS,95621,CA,3,1,1103,Residential,Fri May 16 00:00:00 EDT 2008,170000,38.71641,-121.306239 8884 AMBERJACK WAY,SACRAMENTO,95828,CA,3,2,2161,Residential,Fri May 16 00:00:00 EDT 2008,170250,38.479343,-121.372553 4480 VALLEY HI DR,SACRAMENTO,95823,CA,3,2,1650,Residential,Fri May 16 00:00:00 EDT 2008,173000,38.466781,-121.450955 2250 FOREBAY RD,POLLOCK PINES,95726,CA,3,1,1320,Residential,Fri May 16 00:00:00 EDT 2008,175000,38.77491,-120.597599 3529 FABERGE WAY,SACRAMENTO,95826,CA,3,2,1200,Residential,Fri May 16 00:00:00 EDT 2008,176095,38.553275,-121.346218 1792 DAWNELLE WAY,SACRAMENTO,95835,CA,3,2,1170,Residential,Fri May 16 00:00:00 EDT 2008,176250,38.68271,-121.501697 7800 TABARE CT,CITRUS HEIGHTS,95621,CA,3,2,1199,Residential,Fri May 16 00:00:00 EDT 2008,178000,38.70799,-121.302979 8531 HERMITAGE WAY,SACRAMENTO,95823,CA,4,2,1695,Residential,Fri May 16 00:00:00 EDT 2008,179000,38.448452,-121.428536 2421 BERRYWOOD DR,RANCHO CORDOVA,95670,CA,3,2,1157,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.60868,-121.27849 1005 MORENO WAY,SACRAMENTO,95838,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.646206,-121.442767 1675 VERNON ST Unit 24,ROSEVILLE,95678,CA,3,2,1174,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.734136,-121.299639 24 WINDCHIME CT,SACRAMENTO,95823,CA,3,2,1593,Residential,Fri May 16 00:00:00 EDT 2008,181000,38.44617,-121.427824 540 HARLING CT,RIO LINDA,95673,CA,3,2,1093,Residential,Fri May 16 00:00:00 EDT 2008,182000,38.68279,-121.453509 1207 CRESCENDO DR,ROSEVILLE,95678,CA,3,2,1770,Residential,Fri May 16 00:00:00 EDT 2008,182587,38.72446,-121.292829 7577 EDDYLEE WAY,SACRAMENTO,95822,CA,4,2,1436,Residential,Fri May 16 00:00:00 EDT 2008,185074,38.48291,-121.491509 8369 FOPPIANO WAY,SACRAMENTO,95829,CA,3,2,1124,Residential,Fri May 16 00:00:00 EDT 2008,185833,38.453839,-121.357919 8817 SAWTELLE WAY,SACRAMENTO,95826,CA,4,2,1139,Residential,Fri May 16 00:00:00 EDT 2008,186785,38.565322,-121.374251 1910 BONAVISTA WAY,SACRAMENTO,95832,CA,3,2,1638,Residential,Fri May 16 00:00:00 EDT 2008,187000,38.476048,-121.494961 8 TIDE CT,SACRAMENTO,95833,CA,3,2,1328,Residential,Fri May 16 00:00:00 EDT 2008,188335,38.609864,-121.492304 8952 ROCKY CREEK CT,ELK GROVE,95758,CA,3,2,1273,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.431239,-121.44001 435 EXCHANGE ST,SACRAMENTO,95838,CA,3,1,1082,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.659434,-121.455236 10105 MONTE VALLO CT,SACRAMENTO,95827,CA,4,2,1578,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.573917,-121.316916 3930 ANNABELLE AVE,ROSEVILLE,95661,CA,2,1,796,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.727609,-121.226494 4854 TANGERINE AVE,SACRAMENTO,95823,CA,3,2,1386,Residential,Fri May 16 00:00:00 EDT 2008,191250,38.478239,-121.446326 2909 SHAWN WAY,RANCHO CORDOVA,95670,CA,3,2,1452,Residential,Fri May 16 00:00:00 EDT 2008,193000,38.589925,-121.299059 4290 BLACKFORD WAY,SACRAMENTO,95823,CA,3,2,1513,Residential,Fri May 16 00:00:00 EDT 2008,193500,38.470494,-121.454162 5890 TT TRAK,FORESTHILL,95631,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,194818,39.020808,-120.821518 7015 WOODSIDE DR,SACRAMENTO,95842,CA,4,2,1578,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.693071,-121.332365 6019 CHESHIRE WAY,CITRUS HEIGHTS,95610,CA,4,3,1736,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.676437,-121.279165 3330 VILLAGE CT,CAMERON PARK,95682,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.690504,-120.996245 2561 VERNA WAY,SACRAMENTO,95821,CA,3,1,1473,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.611055,-121.369964 3522 22ND AVE,SACRAMENTO,95820,CA,3,1,1150,Residential,Fri May 16 00:00:00 EDT 2008,198000,38.532725,-121.469078 2880 CANDIDO DR,SACRAMENTO,95833,CA,3,2,1127,Residential,Fri May 16 00:00:00 EDT 2008,199900,38.618019,-121.510215 6908 PIN OAK CT,FAIR OAKS,95628,CA,3,1,1144,Residential,Fri May 16 00:00:00 EDT 2008,200000,38.66424,-121.303675 5733 ANGELINA AVE,CARMICHAEL,95608,CA,3,1,972,Residential,Fri May 16 00:00:00 EDT 2008,201000,38.622634,-121.330846 7849 BONNY DOWNS WAY,ELK GROVE,95758,CA,4,2,2306,Residential,Fri May 16 00:00:00 EDT 2008,204918,38.42139,-121.411339 8716 LONGSPUR WAY,ANTELOPE,95843,CA,3,2,1479,Residential,Fri May 16 00:00:00 EDT 2008,205000,38.724083,-121.3584 6320 EL DORADO ST,EL DORADO,95623,CA,2,1,1040,Residential,Fri May 16 00:00:00 EDT 2008,205000,38.678758,-120.844118 2328 DOROTHY JUNE WAY,SACRAMENTO,95838,CA,3,2,1430,Residential,Fri May 16 00:00:00 EDT 2008,205878,38.641727,-121.412703 1986 DANVERS WAY,SACRAMENTO,95832,CA,4,2,1800,Residential,Fri May 16 00:00:00 EDT 2008,207000,38.47723,-121.492568 7901 GAZELLE TRAIL WAY,ANTELOPE,95843,CA,4,2,1953,Residential,Fri May 16 00:00:00 EDT 2008,207744,38.71174,-121.342675 6080 BRIDGECROSS DR,SACRAMENTO,95835,CA,3,2,1120,Residential,Fri May 16 00:00:00 EDT 2008,209000,38.681952,-121.505009 20 GROTH CIR,SACRAMENTO,95834,CA,3,2,1232,Residential,Fri May 16 00:00:00 EDT 2008,210000,38.640807,-121.533522 1900 DANBROOK DR,SACRAMENTO,95835,CA,1,1,984,Condo,Fri May 16 00:00:00 EDT 2008,210944,38.668433,-121.503471 140 VENTO CT,ROSEVILLE,95678,CA,3,2,0,Condo,Fri May 16 00:00:00 EDT 2008,212500,38.793533,-121.289685 8442 KEUSMAN ST,ELK GROVE,95758,CA,4,2,2329,Residential,Fri May 16 00:00:00 EDT 2008,213750,38.449651,-121.414704 9552 SUNLIGHT LN,ELK GROVE,95758,CA,3,2,1351,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.410561,-121.404327 2733 YUMA CT,CAMERON PARK,95682,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.691215,-120.994949 1407 TIFFANY CIR,ROSEVILLE,95661,CA,4,1,1376,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.736392,-121.2664 636 CRESTVIEW DR,DIAMOND SPRINGS,95619,CA,3,2,1300,Residential,Fri May 16 00:00:00 EDT 2008,216033,38.688255,-120.810235 1528 HESKET WAY,SACRAMENTO,95825,CA,4,2,1566,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.593598,-121.403637 2327 32ND ST,SACRAMENTO,95817,CA,2,1,1115,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.557433,-121.47034 1833 2ND AVE,SACRAMENTO,95818,CA,2,1,1032,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.556818,-121.490669 7252 CARRIAGE DR,CITRUS HEIGHTS,95621,CA,4,2,1419,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.698058,-121.294893 9815 PASO FINO WAY,ELK GROVE,95757,CA,3,2,1261,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.404888,-121.443998 5532 ENGLE RD,CARMICHAEL,95608,CA,2,2,1637,Residential,Fri May 16 00:00:00 EDT 2008,220702,38.63173,-121.335286 1139 CLINTON RD,SACRAMENTO,95825,CA,4,2,1776,Multi-Family,Fri May 16 00:00:00 EDT 2008,221250,38.585291,-121.406824 9176 SAGE GLEN WAY,ELK GROVE,95758,CA,3,2,1338,Residential,Fri May 16 00:00:00 EDT 2008,222000,38.423913,-121.439115 9967 HATHERTON WAY,ELK GROVE,95757,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,222500,38.3052,-121.4033 9264 BOULDER RIVER WAY,ELK GROVE,95624,CA,5,2,2254,Residential,Fri May 16 00:00:00 EDT 2008,222750,38.421713,-121.345191 320 GROTH CIR,SACRAMENTO,95834,CA,3,2,1441,Residential,Fri May 16 00:00:00 EDT 2008,225000,38.638882,-121.531883 137 GUNNISON AVE,SACRAMENTO,95838,CA,4,2,1991,Residential,Fri May 16 00:00:00 EDT 2008,225000,38.650729,-121.466483 8209 RIVALLO WAY,SACRAMENTO,95829,CA,4,3,2126,Residential,Fri May 16 00:00:00 EDT 2008,228750,38.459524,-121.3501 8637 PERIWINKLE CIR,ELK GROVE,95624,CA,3,2,1094,Residential,Fri May 16 00:00:00 EDT 2008,229000,38.443184,-121.364388 3425 MEADOW WAY,ROCKLIN,95677,CA,3,2,1462,Residential,Fri May 16 00:00:00 EDT 2008,230095,38.798028,-121.235364 107 JARVIS CIR,SACRAMENTO,95834,CA,5,3,2258,Residential,Fri May 16 00:00:00 EDT 2008,232500,38.639891,-121.537603 2319 THORES ST,RANCHO CORDOVA,95670,CA,3,2,1074,Residential,Fri May 16 00:00:00 EDT 2008,233000,38.59675,-121.312716 8935 MOUNTAIN HOME CT,ELK GROVE,95624,CA,4,2,2111,Residential,Fri May 16 00:00:00 EDT 2008,233500,38.38751,-121.370276 2566 SERENATA WAY,SACRAMENTO,95835,CA,3,2,1686,Residential,Fri May 16 00:00:00 EDT 2008,239000,38.671556,-121.520916 4085 COUNTRY DR,ANTELOPE,95843,CA,4,3,1915,Residential,Fri May 16 00:00:00 EDT 2008,240000,38.706209,-121.369509 9297 TROUT WAY,ELK GROVE,95624,CA,4,2,2367,Residential,Fri May 16 00:00:00 EDT 2008,240000,38.420637,-121.375798 7 ARCHIBALD CT,SACRAMENTO,95823,CA,3,2,1962,Residential,Fri May 16 00:00:00 EDT 2008,240971,38.443305,-121.435296 11130 EEL RIVER CT,RANCHO CORDOVA,95670,CA,2,2,1406,Residential,Fri May 16 00:00:00 EDT 2008,242000,38.625932,-121.271517 8323 REDBANK WAY,SACRAMENTO,95829,CA,3,2,1789,Residential,Fri May 16 00:00:00 EDT 2008,243450,38.455753,-121.349273 16 BRONCO CREEK CT,SACRAMENTO,95835,CA,4,2,1876,Residential,Fri May 16 00:00:00 EDT 2008,243500,38.674226,-121.525497 8316 NORTHAM DR,ANTELOPE,95843,CA,3,2,1235,Residential,Fri May 16 00:00:00 EDT 2008,246544,38.720767,-121.376678 4240 WINJE DR,ANTELOPE,95843,CA,4,2,2504,Residential,Fri May 16 00:00:00 EDT 2008,246750,38.70884,-121.359559 3569 SODA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,247000,38.631139,-121.501879 5118 ROBANDER ST,CARMICHAEL,95608,CA,3,2,1676,Residential,Fri May 16 00:00:00 EDT 2008,247000,38.657267,-121.310352 5976 KYLENCH CT,CITRUS HEIGHTS,95621,CA,3,2,1367,Residential,Fri May 16 00:00:00 EDT 2008,249000,38.708966,-121.32467 9247 DELAIR WAY,ELK GROVE,95758,CA,4,3,1899,Residential,Fri May 16 00:00:00 EDT 2008,249000,38.422241,-121.458022 9054 DESCENDANT DR,ELK GROVE,95758,CA,3,2,1636,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.428852,-121.415628 3450 WHITNOR CT,SACRAMENTO,95821,CA,3,2,1828,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.627698,-121.369698 6288 LONETREE BLVD,ROCKLIN,95765,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.804993,-121.293609 9355 MATADOR WAY,SACRAMENTO,95826,CA,4,2,1438,Residential,Fri May 16 00:00:00 EDT 2008,252000,38.555633,-121.350691 8671 SUMMER SUN WAY,ELK GROVE,95624,CA,3,2,1451,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.442845,-121.373272 1890 GENEVA PL,SACRAMENTO,95825,CA,3,1,1520,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.599449,-121.400305 1813 AVENIDA MARTINA,ROSEVILLE,95747,CA,3,2,1506,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.776649,-121.339589 191 BARNHART CIR,SACRAMENTO,95835,CA,4,2,2605,Residential,Fri May 16 00:00:00 EDT 2008,257200,38.675594,-121.515878 6221 GREEN TOP WAY,ORANGEVALE,95662,CA,3,2,1196,Residential,Fri May 16 00:00:00 EDT 2008,260000,38.679409,-121.219107 2298 PRIMROSE LN,LINCOLN,95648,CA,3,2,1621,Residential,Fri May 16 00:00:00 EDT 2008,260000,38.89918,-121.322514 5635 LOS PUEBLOS WAY,SACRAMENTO,95835,CA,3,2,1811,Residential,Fri May 16 00:00:00 EDT 2008,263500,38.679191,-121.537622 10165 LOFTON WAY,ELK GROVE,95757,CA,3,2,1540,Residential,Fri May 16 00:00:00 EDT 2008,266510,38.387708,-121.436522 1251 GREEN RAVINE DR,LINCOLN,95648,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,267750,38.88156,-121.301343 6001 SHOO FLY RD,PLACERVILLE,95667,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,270000,38.813546,-120.809254 3040 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,271000,38.770835,-121.366996 2674 TAM O SHANTER DR,EL DORADO HILLS,95762,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,272700,38.695801,-121.079216 6007 MARYBELLE LN,SHINGLE SPRINGS,95682,CA,0,0,0,Unkown,Fri May 16 00:00:00 EDT 2008,275000,38.64347,-120.888183 9949 NESTLING CIR,ELK GROVE,95757,CA,3,2,1543,Residential,Fri May 16 00:00:00 EDT 2008,275000,38.397455,-121.468391 2915 HOLDREGE WAY,SACRAMENTO,95835,CA,5,3,2494,Residential,Fri May 16 00:00:00 EDT 2008,276000,38.663728,-121.525833 2678 BRIARTON DR,LINCOLN,95648,CA,3,2,1650,Residential,Fri May 16 00:00:00 EDT 2008,276500,38.844116,-121.274806 294 SPARROW DR,GALT,95632,CA,4,3,2214,Residential,Fri May 16 00:00:00 EDT 2008,278000,38.258976,-121.321266 2987 DIORITE WAY,SACRAMENTO,95835,CA,5,3,2280,Residential,Fri May 16 00:00:00 EDT 2008,279000,38.667332,-121.528276 6326 APPIAN WAY,CARMICHAEL,95608,CA,3,2,1443,Residential,Fri May 16 00:00:00 EDT 2008,280000,38.66266,-121.316858 6905 COBALT WAY,CITRUS HEIGHTS,95621,CA,4,2,1582,Residential,Fri May 16 00:00:00 EDT 2008,280000,38.691393,-121.305215 8986 HAFLINGER WAY,ELK GROVE,95757,CA,3,2,1857,Residential,Fri May 16 00:00:00 EDT 2008,285000,38.397923,-121.450219 2916 BABSON DR,ELK GROVE,95758,CA,3,2,1735,Residential,Fri May 16 00:00:00 EDT 2008,288000,38.417191,-121.473897 10133 NEBBIOLO CT,ELK GROVE,95624,CA,4,3,2096,Residential,Fri May 16 00:00:00 EDT 2008,289000,38.391085,-121.347231 1103 COMMONS DR,SACRAMENTO,95825,CA,3,2,1720,Residential,Fri May 16 00:00:00 EDT 2008,290000,38.567865,-121.410699 4636 TEAL BAY CT,ANTELOPE,95843,CA,4,2,2160,Residential,Fri May 16 00:00:00 EDT 2008,290000,38.704554,-121.354753 1524 YOUNGS AVE,SACRAMENTO,95838,CA,4,2,1382,Residential,Fri May 16 00:00:00 EDT 2008,293996,38.644927,-121.43054 865 CONRAD CT,PLACERVILLE,95667,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,294000,38.729993,-120.802458 8463 TERRACOTTA CT,ELK GROVE,95624,CA,4,2,1721,Residential,Fri May 16 00:00:00 EDT 2008,294173,38.450548,-121.363002 5747 KING RD,LOOMIS,95650,CA,4,2,1328,Residential,Fri May 16 00:00:00 EDT 2008,295000,38.825096,-121.198432 8253 KEEGAN WAY,ELK GROVE,95624,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,298000,38.446286,-121.400817 9204 TROUT WAY,ELK GROVE,95624,CA,4,2,1982,Residential,Fri May 16 00:00:00 EDT 2008,298000,38.422221,-121.375799 1828 2ND AVE,SACRAMENTO,95818,CA,2,1,1144,Residential,Fri May 16 00:00:00 EDT 2008,299000,38.556844,-121.490769 1113 COMMONS DR,SACRAMENTO,95825,CA,2,2,1623,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.567795,-121.410703 2341 BIG STRIKE TRL,COOL,95614,CA,3,2,1457,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.905927,-120.975169 9452 RED SPRUCE WAY,ELK GROVE,95624,CA,6,3,2555,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.404505,-121.346938 5776 TERRACE DR,ROCKLIN,95765,CA,3,2,1577,Residential,Fri May 16 00:00:00 EDT 2008,300567,38.800539,-121.260979 5908 MCLEAN DR,ELK GROVE,95757,CA,5,3,2592,Residential,Fri May 16 00:00:00 EDT 2008,303000,38.38912,-121.434389 8215 PEREGRINE WAY,CITRUS HEIGHTS,95610,CA,3,2,1401,Residential,Fri May 16 00:00:00 EDT 2008,305000,38.715493,-121.26293 1104 HILLSDALE LN,LINCOLN,95648,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,306000,38.865017,-121.32302 2949 PANAMA AVE,CARMICHAEL,95608,CA,3,2,1502,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.618369,-121.326187 1356 HARTLEY WAY,FOLSOM,95630,CA,3,2,1327,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.651617,-121.131674 633 HANISCH DR,ROSEVILLE,95678,CA,4,3,1800,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.76349,-121.275881 63 ANGEL ISLAND CIR,SACRAMENTO,95831,CA,4,2,2169,Residential,Fri May 16 00:00:00 EDT 2008,311518,38.490408,-121.547664 1571 WILD OAK LN,LINCOLN,95648,CA,5,3,2457,Residential,Fri May 16 00:00:00 EDT 2008,312000,38.844144,-121.274174 5222 COPPER SUNSET WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,313000,38.529181,-121.224755 5601 SPINDRIFT LN,ORANGEVALE,95662,CA,4,2,2004,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.668289,-121.192316 652 FIFTEEN MILE DR,ROSEVILLE,95678,CA,4,3,2212,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.775872,-121.298864 7921 DOE TRAIL WAY,ANTELOPE,95843,CA,5,3,3134,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.711927,-121.343608 4204 LUSK DR,SACRAMENTO,95864,CA,3,2,1360,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.606569,-121.368424 5321 DELTA DR,ROCKLIN,95765,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.815493,-121.262908 5608 ROSEDALE WAY,SACRAMENTO,95822,CA,3,2,1276,Residential,Fri May 16 00:00:00 EDT 2008,320000,38.525115,-121.518689 3372 BERETANIA WAY,SACRAMENTO,95834,CA,4,3,2962,Residential,Fri May 16 00:00:00 EDT 2008,322000,38.64977,-121.53448 2422 STEFANIE DR,ROCKLIN,95765,CA,4,2,1888,Residential,Fri May 16 00:00:00 EDT 2008,325000,38.82273,-121.26424 3232 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,325500,38.772821,-121.364821 448 ELMWOOD CT,ROSEVILLE,95678,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,326951,38.771917,-121.304439 1214 DAWNWOOD DR,GALT,95632,CA,3,2,1548,Residential,Fri May 16 00:00:00 EDT 2008,328370,38.290119,-121.286023 1440 EMERALD LN,LINCOLN,95648,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,330000,38.861864,-121.267478 3349 CORVINA DR,RANCHO CORDOVA,95670,CA,4,3,2109,Residential,Fri May 16 00:00:00 EDT 2008,330000,38.580545,-121.279016 10254 JULIANA WAY,SACRAMENTO,95827,CA,4,2,2484,Residential,Fri May 16 00:00:00 EDT 2008,331200,38.56803,-121.309966 149 OPUS CIR,SACRAMENTO,95834,CA,4,3,2258,Residential,Fri May 16 00:00:00 EDT 2008,332000,38.6354,-121.53499 580 REGENCY PARK CIR,SACRAMENTO,95835,CA,3,3,2212,Residential,Fri May 16 00:00:00 EDT 2008,334000,38.674864,-121.4958 5544 CAMAS CT,ORANGEVALE,95662,CA,3,2,1616,Residential,Fri May 16 00:00:00 EDT 2008,335000,38.667703,-121.209456 5102 ARCHCREST WAY,SACRAMENTO,95835,CA,4,2,2372,Residential,Fri May 16 00:00:00 EDT 2008,341000,38.66841,-121.494639 5725 BALFOR RD,ROCKLIN,95765,CA,5,3,2606,Residential,Fri May 16 00:00:00 EDT 2008,346375,38.807816,-121.270008 7697 ROSEHALL DR,ROSEVILLE,95678,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,347225,38.79218,-121.28595 4821 HUTSON WAY,ELK GROVE,95757,CA,5,3,2877,Residential,Fri May 16 00:00:00 EDT 2008,349000,38.386239,-121.448159 4509 WINJE DR,ANTELOPE,95843,CA,3,2,2960,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.709513,-121.359357 1965 LAURELHURST LN,LINCOLN,95648,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.853869,-121.271742 6709 ROSE BRIDGE DR,ROSEVILLE,95678,CA,3,2,2172,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.792461,-121.275711 281 SPYGLASS HL,ROSEVILLE,95678,CA,3,2,2100,Condo,Fri May 16 00:00:00 EDT 2008,350000,38.762153,-121.283451 7709 RIVER VILLAGE DR,SACRAMENTO,95831,CA,3,2,1795,Residential,Fri May 16 00:00:00 EDT 2008,351000,38.483212,-121.54019 4165 BRISBANE CIR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,356200,38.686067,-121.073413 506 BEDFORD CT,ROSEVILLE,95661,CA,4,2,2295,Residential,Fri May 16 00:00:00 EDT 2008,360000,38.733985,-121.236766 9048 PINTO CANYON WAY,ROSEVILLE,95747,CA,4,3,2577,Residential,Fri May 16 00:00:00 EDT 2008,367463,38.792493,-121.331899 2274 IVY BRIDGE DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,375000,38.778561,-121.362008 14004 WALNUT AVE,WALNUT GROVE,95690,CA,3,1,1727,Residential,Fri May 16 00:00:00 EDT 2008,380000,38.247659,-121.515129 6905 FRANKFORT CT,ELK GROVE,95758,CA,3,2,1485,Residential,Fri May 16 00:00:00 EDT 2008,380578,38.429139,-121.423444 3621 WINTUN DR,CARMICHAEL,95608,CA,3,2,1655,Residential,Fri May 16 00:00:00 EDT 2008,386222,38.629929,-121.323086 201 KIRKLAND CT,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,389000,38.867125,-121.319085 12075 APPLESBURY CT,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,390000,38.5357,-121.2249 1975 SIDESADDLE WAY,ROSEVILLE,95661,CA,3,2,2049,Residential,Fri May 16 00:00:00 EDT 2008,395500,38.737872,-121.249025 5420 ALMOND FALLS WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,396000,38.527384,-121.233531 9677 PILLITERI CT,ELK GROVE,95757,CA,5,3,2875,Residential,Fri May 16 00:00:00 EDT 2008,397000,38.405571,-121.445186 1515 EL CAMINO VERDE DR,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,400000,38.904869,-121.32075 556 PLATT CIR,EL DORADO HILLS,95762,CA,4,2,2199,Residential,Fri May 16 00:00:00 EDT 2008,400000,38.656299,-121.079783 1792 DIAMOND WOODS CIR,ROSEVILLE,95747,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,412500,38.808581,-121.32785 1124 PERKINS WAY,SACRAMENTO,95818,CA,2,1,1304,Residential,Fri May 16 00:00:00 EDT 2008,413500,38.551611,-121.504437 4748 SALEM WAY,CARMICHAEL,95608,CA,3,2,2334,Residential,Fri May 16 00:00:00 EDT 2008,415000,38.634111,-121.353376 1484 RADCLIFFE WAY,AUBURN,95603,CA,4,3,2278,Residential,Fri May 16 00:00:00 EDT 2008,420454,38.935579,-121.079018 51 AIKEN WAY,SACRAMENTO,95819,CA,3,1,1493,Residential,Fri May 16 00:00:00 EDT 2008,425000,38.579326,-121.44252 2818 KNOLLWOOD DR,CAMERON PARK,95682,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,425000,38.669805,-120.999007 1536 STONEY CROSS LN,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,433500,38.860007,-121.310946 509 CASTILLIAN CT,ROSEVILLE,95747,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,438000,38.804773,-121.341195 700 HUNTER PL,FOLSOM,95630,CA,5,3,2787,Residential,Fri May 16 00:00:00 EDT 2008,441000,38.66051,-121.163689 1240 FAY CIR,SACRAMENTO,95831,CA,5,3,2824,Residential,Fri May 16 00:00:00 EDT 2008,445000,38.506371,-121.514456 1113 SANDWICK WAY,FOLSOM,95630,CA,4,3,3261,Residential,Fri May 16 00:00:00 EDT 2008,446000,38.673882,-121.105077 3108 DELWOOD WAY,SACRAMENTO,95821,CA,4,2,2053,Residential,Fri May 16 00:00:00 EDT 2008,450000,38.621566,-121.370882 3212 CORNICHE LN,ROSEVILLE,95661,CA,4,3,2379,Residential,Fri May 16 00:00:00 EDT 2008,455000,38.750577,-121.232768 2159 BECKETT DR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,460000,38.680092,-121.036467 4320 FOUR SEASONS RD,PLACERVILLE,95667,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,475000,38.690867,-120.693641 6401 MARSHALL RD,GARDEN VALLEY,95633,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,490000,38.84255,-120.8754 2089 BECKETT DR,EL DORADO HILLS,95762,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,493000,38.681778,-121.035838 6196 EDGEHILL DR,EL DORADO HILLS,95762,CA,5,4,0,Residential,Fri May 16 00:00:00 EDT 2008,508000,38.676131,-121.038931 200 HILLSFORD CT,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,511000,38.780051,-121.378718 8217 PLUMERIA AVE,FAIR OAKS,95628,CA,3,2,3173,Residential,Fri May 16 00:00:00 EDT 2008,525000,38.650735,-121.258628 4841 VILLAGE GREEN DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,533000,38.664066,-121.056735 3863 LAS PASAS WAY,SACRAMENTO,95864,CA,3,1,1348,Residential,Fri May 16 00:00:00 EDT 2008,545000,38.588936,-121.373606 820 DANA CT,AUBURN,95603,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,560000,38.865246,-121.094869 1165 37TH ST,SACRAMENTO,95816,CA,2,1,1252,Residential,Fri May 16 00:00:00 EDT 2008,575000,38.568438,-121.457854 203 CASCADE FALLS DR,FOLSOM,95630,CA,4,3,3229,Residential,Fri May 16 00:00:00 EDT 2008,575000,38.703962,-121.1871 9880 IZILDA CT,SACRAMENTO,95829,CA,5,4,3863,Residential,Fri May 16 00:00:00 EDT 2008,598695,38.45326,-121.32573 1800 AVONDALE DR,ROSEVILLE,95747,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.798448,-121.344054 4620 BROMWICH CT,ROCKLIN,95677,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.772672,-121.220232 620 KESWICK CT,GRANITE BAY,95746,CA,4,3,2356,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.732096,-121.219142 4478 GREENBRAE RD,ROCKLIN,95677,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.781134,-121.222801 8432 BRIGGS DR,ROSEVILLE,95747,CA,5,3,3579,Residential,Fri May 16 00:00:00 EDT 2008,610000,38.78861,-121.339495 200 CRADLE MOUNTAIN CT,EL DORADO HILLS,95762,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,622500,38.6478,-121.0309 2065 IMPRESSIONIST WAY,EL DORADO HILLS,95762,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,680000,38.682961,-121.033253 2982 ABERDEEN LN,EL DORADO HILLS,95762,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,879000,38.706692,-121.058869 9401 BARREL RACER CT,WILTON,95693,CA,4,3,4400,Residential,Fri May 16 00:00:00 EDT 2008,884790,38.415298,-121.194858 3720 VISTA DE MADERA,LINCOLN,95648,CA,3,3,0,Residential,Fri May 16 00:00:00 EDT 2008,1551,38.851645,-121.231742 14151 INDIO DR,SLOUGHHOUSE,95683,CA,3,4,5822,Residential,Fri May 16 00:00:00 EDT 2008,2000,38.490447,-121.129337 7401 TOULON LN,SACRAMENTO,95828,CA,4,2,1512,Residential,Thu May 15 00:00:00 EDT 2008,56950,38.488628,-121.387759 9127 NEWHALL DR Unit 34,SACRAMENTO,95826,CA,1,1,611,Condo,Thu May 15 00:00:00 EDT 2008,60000,38.542419,-121.359904 5937 BAMFORD DR,SACRAMENTO,95823,CA,2,1,876,Residential,Thu May 15 00:00:00 EDT 2008,61000,38.471139,-121.432255 5672 HILLSDALE BLVD,SACRAMENTO,95842,CA,2,1,933,Condo,Thu May 15 00:00:00 EDT 2008,62000,38.670467,-121.359799 3920 39TH ST,SACRAMENTO,95820,CA,2,1,864,Residential,Thu May 15 00:00:00 EDT 2008,68566,38.539213,-121.46393 701 JESSIE AVE,SACRAMENTO,95838,CA,2,1,1011,Residential,Thu May 15 00:00:00 EDT 2008,70000,38.643978,-121.449562 83 ARCADE BLVD,SACRAMENTO,95815,CA,4,2,1158,Residential,Thu May 15 00:00:00 EDT 2008,80000,38.618716,-121.466327 601 REGGINALD WAY,SACRAMENTO,95838,CA,3,2,1092,Residential,Thu May 15 00:00:00 EDT 2008,85500,38.64472,-121.452228 550 DEL VERDE CIR,SACRAMENTO,95833,CA,2,1,956,Condo,Thu May 15 00:00:00 EDT 2008,92000,38.627147,-121.500799 4113 DAYSTAR CT,SACRAMENTO,95824,CA,2,2,1139,Residential,Thu May 15 00:00:00 EDT 2008,93600,38.520469,-121.458606 7374 TISDALE WAY,SACRAMENTO,95822,CA,3,1,1058,Residential,Thu May 15 00:00:00 EDT 2008,95000,38.488238,-121.472561 3348 RIO LINDA BLVD,SACRAMENTO,95838,CA,3,2,1040,Residential,Thu May 15 00:00:00 EDT 2008,97750,38.628842,-121.446127 3935 LIMESTONE WAY,SACRAMENTO,95823,CA,3,2,1354,Residential,Thu May 15 00:00:00 EDT 2008,104000,38.484374,-121.463157 6208 GRATTAN WAY,NORTH HIGHLANDS,95660,CA,3,1,1051,Residential,Thu May 15 00:00:00 EDT 2008,105000,38.679279,-121.376615 739 E WOODSIDE LN Unit E,SACRAMENTO,95825,CA,1,1,682,Condo,Thu May 15 00:00:00 EDT 2008,107666,38.578675,-121.409951 4225 46TH AVE,SACRAMENTO,95824,CA,3,1,1161,Residential,Thu May 15 00:00:00 EDT 2008,109000,38.511893,-121.457676 1434 BELL AVE,SACRAMENTO,95838,CA,3,1,1004,Residential,Thu May 15 00:00:00 EDT 2008,110000,38.647398,-121.432914 5628 GEORGIA DR,NORTH HIGHLANDS,95660,CA,3,1,1229,Residential,Thu May 15 00:00:00 EDT 2008,110000,38.669587,-121.379879 7629 BETH ST,SACRAMENTO,95832,CA,3,2,1249,Residential,Thu May 15 00:00:00 EDT 2008,112500,38.480126,-121.487869 2277 BABETTE WAY,SACRAMENTO,95832,CA,3,2,1161,Residential,Thu May 15 00:00:00 EDT 2008,114800,38.479593,-121.48434 6561 WEATHERFORD WAY,SACRAMENTO,95823,CA,3,1,1010,Residential,Thu May 15 00:00:00 EDT 2008,116000,38.465551,-121.42661 3035 ESTEPA DR Unit 5C,CAMERON PARK,95682,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,119000,38.681393,-120.996713 5136 CABOT CIR,SACRAMENTO,95820,CA,4,2,1462,Residential,Thu May 15 00:00:00 EDT 2008,121500,38.528479,-121.411806 7730 ROBINETTE RD,SACRAMENTO,95828,CA,3,2,1269,Residential,Thu May 15 00:00:00 EDT 2008,122000,38.47709,-121.410569 87 LACAM CIR,SACRAMENTO,95820,CA,2,2,1188,Residential,Thu May 15 00:00:00 EDT 2008,123675,38.532359,-121.41167 1691 NOGALES ST,SACRAMENTO,95838,CA,4,2,1570,Residential,Thu May 15 00:00:00 EDT 2008,126854,38.631925,-121.427775 3118 42ND ST,SACRAMENTO,95817,CA,3,2,1093,Residential,Thu May 15 00:00:00 EDT 2008,127059,38.546091,-121.457745 7517 50TH AVE,SACRAMENTO,95828,CA,3,1,962,Residential,Thu May 15 00:00:00 EDT 2008,128687,38.507339,-121.416267 4071 EVALITA WAY,SACRAMENTO,95823,CA,3,2,1089,Residential,Thu May 15 00:00:00 EDT 2008,129500,38.466388,-121.458861 7928 36TH AVE,SACRAMENTO,95824,CA,3,2,1127,Residential,Thu May 15 00:00:00 EDT 2008,130000,38.52049,-121.411383 6631 DEMARET DR,SACRAMENTO,95822,CA,4,2,1309,Residential,Thu May 15 00:00:00 EDT 2008,131750,38.506382,-121.483574 7043 9TH AVE,RIO LINDA,95673,CA,2,1,970,Residential,Thu May 15 00:00:00 EDT 2008,132000,38.695589,-121.444133 97 KENNELFORD CIR,SACRAMENTO,95823,CA,3,2,1144,Residential,Thu May 15 00:00:00 EDT 2008,134000,38.462376,-121.426556 2636 TRONERO WAY,RANCHO CORDOVA,95670,CA,3,1,1000,Residential,Thu May 15 00:00:00 EDT 2008,134000,38.593049,-121.30304 1530 TOPANGA LN Unit 204,LINCOLN,95648,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,138000,38.88415,-121.270277 3604 KODIAK WAY,ANTELOPE,95843,CA,3,2,1206,Residential,Thu May 15 00:00:00 EDT 2008,142000,38.706175,-121.379776 2149 COTTAGE WAY,SACRAMENTO,95825,CA,3,1,1285,Residential,Thu May 15 00:00:00 EDT 2008,143012,38.603593,-121.417011 8632 PRAIRIEWOODS DR,SACRAMENTO,95828,CA,3,2,1543,Residential,Thu May 15 00:00:00 EDT 2008,145846,38.477563,-121.384382 612 STONE BLVD,WEST SACRAMENTO,95691,CA,2,1,884,Residential,Thu May 15 00:00:00 EDT 2008,147000,38.563084,-121.535579 4180 12TH AVE,SACRAMENTO,95817,CA,3,1,1019,Residential,Thu May 15 00:00:00 EDT 2008,148750,38.54117,-121.458129 8025 ARROYO VISTA DR,SACRAMENTO,95823,CA,4,2,1392,Residential,Thu May 15 00:00:00 EDT 2008,150000,38.46654,-121.419029 5754 WALERGA RD Unit 4,SACRAMENTO,95842,CA,2,1,924,Condo,Thu May 15 00:00:00 EDT 2008,150454,38.672567,-121.356754 8 LA ROCAS CT,SACRAMENTO,95823,CA,3,2,1217,Residential,Thu May 15 00:00:00 EDT 2008,151087,38.46616,-121.448283 8636 LONGSPUR WAY,ANTELOPE,95843,CA,3,2,1670,Residential,Thu May 15 00:00:00 EDT 2008,157296,38.725873,-121.35856 1941 EXPEDITION WAY,SACRAMENTO,95832,CA,3,2,1302,Residential,Thu May 15 00:00:00 EDT 2008,157500,38.473775,-121.493777 4351 TURNBRIDGE DR,SACRAMENTO,95823,CA,3,2,1488,Residential,Thu May 15 00:00:00 EDT 2008,160000,38.502034,-121.456027 6513 HOLIDAY WAY,NORTH HIGHLANDS,95660,CA,3,2,1373,Residential,Thu May 15 00:00:00 EDT 2008,160000,38.685361,-121.376938 8321 MISTLETOE WAY,CITRUS HEIGHTS,95621,CA,4,2,1381,Residential,Thu May 15 00:00:00 EDT 2008,161250,38.717738,-121.308322 5920 VALLEY GLEN WAY,SACRAMENTO,95823,CA,3,2,1265,Residential,Thu May 15 00:00:00 EDT 2008,164000,38.462821,-121.433135 2601 SAN FERNANDO WAY,SACRAMENTO,95818,CA,2,1,881,Residential,Thu May 15 00:00:00 EDT 2008,165000,38.556178,-121.476256 501 POPLAR AVE,WEST SACRAMENTO,95691,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,165000,38.584526,-121.534609 8008 SAINT HELENA CT,SACRAMENTO,95829,CA,4,2,1608,Residential,Thu May 15 00:00:00 EDT 2008,165750,38.467012,-121.359969 6517 DONEGAL DR,CITRUS HEIGHTS,95621,CA,3,1,1344,Residential,Thu May 15 00:00:00 EDT 2008,166000,38.681554,-121.312934 1001 RIO NORTE WAY,SACRAMENTO,95834,CA,3,2,1202,Residential,Thu May 15 00:00:00 EDT 2008,169000,38.634292,-121.485106 604 P ST,LINCOLN,95648,CA,3,2,1104,Residential,Thu May 15 00:00:00 EDT 2008,170000,38.893168,-121.305398 10001 WOODCREEK OAKS BLVD Unit 815,ROSEVILLE,95747,CA,2,2,0,Condo,Thu May 15 00:00:00 EDT 2008,170000,38.795529,-121.328819 7351 GIGI PL,SACRAMENTO,95828,CA,4,2,1859,Multi-Family,Thu May 15 00:00:00 EDT 2008,170000,38.490606,-121.410173 7740 DIXIE LOU ST,SACRAMENTO,95832,CA,3,2,1232,Residential,Thu May 15 00:00:00 EDT 2008,170000,38.475853,-121.477039 7342 DAVE ST,SACRAMENTO,95828,CA,3,1,1638,Residential,Thu May 15 00:00:00 EDT 2008,170725,38.490822,-121.401643 7687 HOWERTON DR,SACRAMENTO,95831,CA,2,2,1177,Residential,Thu May 15 00:00:00 EDT 2008,171750,38.480859,-121.539745 26 KAMSON CT,SACRAMENTO,95833,CA,3,2,1582,Residential,Thu May 15 00:00:00 EDT 2008,172000,38.622794,-121.499173 7045 PEEVEY CT,SACRAMENTO,95823,CA,2,2,904,Residential,Thu May 15 00:00:00 EDT 2008,173056,38.502254,-121.451444 8916 GABLES MILL PL,ELK GROVE,95758,CA,3,2,1340,Residential,Thu May 15 00:00:00 EDT 2008,174000,38.433919,-121.422347 1140 EDMONTON DR,SACRAMENTO,95833,CA,3,2,1204,Residential,Thu May 15 00:00:00 EDT 2008,174250,38.62457,-121.486913 8879 APPLE PEAR CT,ELK GROVE,95624,CA,4,2,1477,Residential,Thu May 15 00:00:00 EDT 2008,176850,38.44574,-121.3725 9 WIND CT,SACRAMENTO,95823,CA,4,2,1497,Residential,Thu May 15 00:00:00 EDT 2008,179500,38.45073,-121.427528 8570 SHERATON DR,FAIR OAKS,95628,CA,3,1,960,Residential,Thu May 15 00:00:00 EDT 2008,185000,38.667254,-121.240708 1550 TOPANGA LN Unit 207,LINCOLN,95648,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,188000,38.88417,-121.270222 1080 RIO NORTE WAY,SACRAMENTO,95834,CA,3,2,1428,Residential,Thu May 15 00:00:00 EDT 2008,188700,38.634335,-121.486098 5501 VALLETTA WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Thu May 15 00:00:00 EDT 2008,189000,38.530144,-121.43749 5624 MEMORY LN,FAIR OAKS,95628,CA,3,1,1529,Residential,Thu May 15 00:00:00 EDT 2008,189000,38.66745,-121.2364 6622 WILLOWLEAF DR,CITRUS HEIGHTS,95621,CA,4,3,1892,Residential,Thu May 15 00:00:00 EDT 2008,189836,38.699714,-121.311635 27 MEGAN CT,SACRAMENTO,95838,CA,4,2,1887,Residential,Thu May 15 00:00:00 EDT 2008,190000,38.649258,-121.465308 6601 WOODMORE OAKS DR,ORANGEVALE,95662,CA,3,2,1294,Residential,Thu May 15 00:00:00 EDT 2008,191250,38.687006,-121.254319 1973 DANVERS WAY,SACRAMENTO,95832,CA,3,2,1638,Residential,Thu May 15 00:00:00 EDT 2008,191675,38.477568,-121.492574 8001 ARROYO VISTA DR,SACRAMENTO,95823,CA,3,2,1677,Residential,Thu May 15 00:00:00 EDT 2008,195500,38.46734,-121.419843 7409 VOYAGER WAY,CITRUS HEIGHTS,95621,CA,3,1,1073,Residential,Thu May 15 00:00:00 EDT 2008,198000,38.700717,-121.3133 815 CROSSWIND DR,SACRAMENTO,95838,CA,3,2,1231,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.651386,-121.45042 5509 LAGUNA CREST WAY,ELK GROVE,95758,CA,3,2,1175,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.42442,-121.440357 8424 MERRY HILL WAY,ELK GROVE,95624,CA,3,2,1416,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.452075,-121.366461 1525 PENNSYLVANIA AVE,WEST SACRAMENTO,95691,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,200100,38.569943,-121.527539 5954 BRIDGECROSS DR,SACRAMENTO,95835,CA,3,2,1358,Residential,Thu May 15 00:00:00 EDT 2008,201528,38.68197,-121.500025 8789 SEQUOIA WOOD CT,ELK GROVE,95624,CA,4,2,1609,Residential,Thu May 15 00:00:00 EDT 2008,204750,38.438818,-121.37443 6600 SILVERTHORNE CIR,SACRAMENTO,95842,CA,4,3,1968,Residential,Thu May 15 00:00:00 EDT 2008,205000,38.68607,-121.342369 2221 2ND AVE,SACRAMENTO,95818,CA,2,2,1089,Residential,Thu May 15 00:00:00 EDT 2008,205000,38.555781,-121.485331 3230 SMATHERS WAY,CARMICHAEL,95608,CA,3,2,1296,Residential,Thu May 15 00:00:00 EDT 2008,205900,38.623372,-121.347665 5209 LAGUNA CREST WAY,ELK GROVE,95758,CA,2,2,1189,Residential,Thu May 15 00:00:00 EDT 2008,207000,38.424421,-121.443915 416 LEITCH AVE,SACRAMENTO,95815,CA,2,1,795,Residential,Thu May 15 00:00:00 EDT 2008,207973,38.612694,-121.456669 2100 BEATTY WAY,ROSEVILLE,95747,CA,3,2,1371,Residential,Thu May 15 00:00:00 EDT 2008,208250,38.737882,-121.308142 6920 GILLINGHAM WAY,NORTH HIGHLANDS,95660,CA,3,1,1310,Residential,Thu May 15 00:00:00 EDT 2008,208318,38.694279,-121.373395 82 WILDFLOWER DR,GALT,95632,CA,3,2,1262,Residential,Thu May 15 00:00:00 EDT 2008,209347,38.259708,-121.311616 8652 BANTON CIR,ELK GROVE,95624,CA,4,2,1740,Residential,Thu May 15 00:00:00 EDT 2008,211500,38.444,-121.370993 8428 MISTY PASS WAY,ANTELOPE,95843,CA,3,2,1517,Residential,Thu May 15 00:00:00 EDT 2008,212000,38.722959,-121.347115 7958 ROSEVIEW WAY,SACRAMENTO,95828,CA,3,2,1450,Residential,Thu May 15 00:00:00 EDT 2008,213000,38.467836,-121.410366 9020 LUKEN CT,ELK GROVE,95624,CA,3,2,1416,Residential,Thu May 15 00:00:00 EDT 2008,216000,38.451398,-121.366614 7809 VALLECITOS WAY,SACRAMENTO,95828,CA,3,1,888,Residential,Thu May 15 00:00:00 EDT 2008,216021,38.508217,-121.411207 8445 OLD AUBURN RD,CITRUS HEIGHTS,95610,CA,3,2,1882,Residential,Thu May 15 00:00:00 EDT 2008,219000,38.715423,-121.246743 10085 ATKINS DR,ELK GROVE,95757,CA,3,2,1302,Residential,Thu May 15 00:00:00 EDT 2008,219794,38.390893,-121.437821 9185 CERROLINDA CIR,ELK GROVE,95758,CA,3,2,1418,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.424497,-121.426595 9197 CORTINA CIR,ROSEVILLE,95678,CA,3,2,0,Condo,Thu May 15 00:00:00 EDT 2008,220000,38.793152,-121.290025 5429 HESPER WAY,CARMICHAEL,95608,CA,4,2,1319,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.665104,-121.315901 1178 WARMWOOD CT,GALT,95632,CA,4,2,1770,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.289544,-121.284607 4900 ELUDE CT,SACRAMENTO,95842,CA,4,2,1627,Residential,Thu May 15 00:00:00 EDT 2008,223000,38.69674,-121.350519 3557 SODA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,224000,38.631026,-121.501879 3528 SAINT GEORGE DR,SACRAMENTO,95821,CA,3,1,1040,Residential,Thu May 15 00:00:00 EDT 2008,224000,38.629468,-121.376445 7381 WASHBURN WAY,NORTH HIGHLANDS,95660,CA,3,1,960,Residential,Thu May 15 00:00:00 EDT 2008,224252,38.70355,-121.375103 2181 WINTERHAVEN CIR,CAMERON PARK,95682,CA,3,2,0,Residential,Thu May 15 00:00:00 EDT 2008,224500,38.69757,-120.995739 7540 HICKORY AVE,ORANGEVALE,95662,CA,3,1,1456,Residential,Thu May 15 00:00:00 EDT 2008,225000,38.703056,-121.235221 5024 CHAMBERLIN CIR,ELK GROVE,95757,CA,3,2,1450,Residential,Thu May 15 00:00:00 EDT 2008,228000,38.389756,-121.446246 2400 INVERNESS DR,LINCOLN,95648,CA,3,2,1358,Residential,Thu May 15 00:00:00 EDT 2008,229027,38.897814,-121.324691 5 BISHOPGATE CT,SACRAMENTO,95823,CA,4,2,1329,Residential,Thu May 15 00:00:00 EDT 2008,229500,38.467936,-121.445477 5601 REXLEIGH DR,SACRAMENTO,95823,CA,4,2,1715,Residential,Thu May 15 00:00:00 EDT 2008,230000,38.445342,-121.441504 1909 YARNELL WAY,ELK GROVE,95758,CA,3,2,1262,Residential,Thu May 15 00:00:00 EDT 2008,230000,38.417382,-121.484325 9169 GARLINGTON CT,SACRAMENTO,95829,CA,4,3,2280,Residential,Thu May 15 00:00:00 EDT 2008,232425,38.457679,-121.35962 6932 RUSKUT WAY,SACRAMENTO,95823,CA,3,2,1477,Residential,Thu May 15 00:00:00 EDT 2008,234000,38.499893,-121.45889 7933 DAFFODIL WAY,CITRUS HEIGHTS,95610,CA,3,2,1216,Residential,Thu May 15 00:00:00 EDT 2008,235000,38.708824,-121.256803 8304 RED FOX WAY,ELK GROVE,95758,CA,4,2,1685,Residential,Thu May 15 00:00:00 EDT 2008,235301,38.417,-121.397424 3882 YELLOWSTONE LN,EL DORADO HILLS,95762,CA,3,2,1362,Residential,Thu May 15 00:00:00 EDT 2008,235738,38.655245,-121.075915 \ No newline at end of file diff --git a/source/08-text-files/fileuse/__init__.py b/source/08-text-files/fileuse/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/08-text-files/fileuse/binaryfile.py b/source/08-text-files/fileuse/binaryfile.py new file mode 100644 index 0000000..9f0ab16 --- /dev/null +++ b/source/08-text-files/fileuse/binaryfile.py @@ -0,0 +1,42 @@ + +def write_file(): + """ + Écrire un fichier binaire très simple. + + En Python, on ne peut pas tout simplement écrire des chaînes dans un + fichier dit binaire. Dans Python 3, on fait la différence entre binaire et texte. + Quand on manipule des fichiers texte, on peut y écrire des données `str`. + Par contre, quand on manipule des fichiers binaires, on manipule des données plus + brutes, de type `bytes` (ou `bytearray`) + + """ + f = open("demo.bin", "wb") + f.write(bytearray([32, 33, 34, 35, 36, 37, 38, 39, 40])) # (9) + f.write(b"Bonjour les amis") # (16) ça passe car les caractères sont ASCII et leur code tient dans un byte + f.write("Bonjour les héros, ça va bien ?".encode("utf-8")) # (33) + f.close() + + +def read_file(): + """ + Lire dans un fichier binaire très simple. + + """ + f = open("demo.bin", "rb") + tableau = f.read(9) + chaine1 = f.read(16) + chaine2 = f.read(33).decode("utf-8") + f.seek(0) + data = f.read() + f.close() + # Afficher les données lues dans le fichier + print(tableau) + print(chaine1) + print(chaine2) + # Pour tester, revenir au début du fichier et tout lire d'une traite + print(data) + + +if __name__ == "__main__": + write_file() + read_file() diff --git a/source/08-text-files/fileuse/demo.bin b/source/08-text-files/fileuse/demo.bin new file mode 100644 index 0000000..c573a71 --- /dev/null +++ b/source/08-text-files/fileuse/demo.bin @@ -0,0 +1 @@ + !"#$%&'(Bonjour les amisBonjour les héros, ça va bien ? \ No newline at end of file diff --git a/source/08-text-files/fileuse/demo.txt b/source/08-text-files/fileuse/demo.txt new file mode 100644 index 0000000..9940519 --- /dev/null +++ b/source/08-text-files/fileuse/demo.txt @@ -0,0 +1 @@ +Contenu de notre fichier texte de démo ! \ No newline at end of file diff --git a/source/08-text-files/fileuse/filemanager.py b/source/08-text-files/fileuse/filemanager.py new file mode 100644 index 0000000..e3910bf --- /dev/null +++ b/source/08-text-files/fileuse/filemanager.py @@ -0,0 +1,43 @@ + +with open("demo.txt", "r", encoding="utf-8") as f: + pass + +# écrire un manager +class File(object): + def __init__(self, file_name, method): + self.file_obj = open(file_name, method) + def __enter__(self): + return self.file_obj + def __exit__(self, type, value, traceback): + self.file_obj.close() + +# Just by defining __enter__ and __exit__ methods we can use our new class in a with statement. Let’s try: +# +# with File('demo.txt', 'w') as opened_file: +# opened_file.write('Hola!') +# +# Our __exit__ method accepts three arguments. They are required by every __exit__ method which is a part of a Context Manager class. Let’s talk about what happens under-the-hood. +# +# The with statement stores the __exit__ method of the File class. +# It calls the __enter__ method of the File class. +# The __enter__ method opens the file and returns it. +# The opened file handle is passed to opened_file. +# We write to the file using .write(). +# The with statement calls the stored __exit__ method. +# The __exit__ method closes the file. + + +# We did not talk about the type, value and traceback arguments of the __exit__ method. Between the 4th and 6th step, if an exception occurs, Python passes the type, value and traceback of the exception to the __exit__ method. It allows the __exit__ method to decide how to close the file and if any further steps are required. In our case we are not paying any attention to them. +# +# What if our file object raises an exception? We might be trying to access a method on the file object which it does not supports. For instance: +# +# with File('demo.txt', 'w') as opened_file: +# opened_file.undefined_function('Hola!') +# +# Let’s list the steps which are taken by the with statement when an error is encountered: +# +# It passes the type, value and traceback of the error to the __exit__ method. +# It allows the __exit__ method to handle the exception. +# If __exit__ returns True then the exception was gracefully handled. +# If anything other than True is returned by the __exit__ method then the exception is raised by the with statement. + diff --git a/source/08-text-files/fileuse/filesearch.py b/source/08-text-files/fileuse/filesearch.py new file mode 100644 index 0000000..71e580c --- /dev/null +++ b/source/08-text-files/fileuse/filesearch.py @@ -0,0 +1,12 @@ +import os, glob + +# traverse root directory, and list directories as dirs and files as files +for root, dirs, files in os.walk("/home/steve/Code/python/initiation"): + for filename in files: + path = os.path.join(root, filename) + print(path) + + +# https://docs.python.org/fr/3/library/glob.html +files = glob.glob("/home/steve/Code/python/initiation/**/*.py", recursive=True) +print(files) \ No newline at end of file diff --git a/source/08-text-files/fileuse/textfile.py b/source/08-text-files/fileuse/textfile.py new file mode 100644 index 0000000..342486d --- /dev/null +++ b/source/08-text-files/fileuse/textfile.py @@ -0,0 +1,25 @@ + +def write_file(): + """ + Écrire un fichier texte très simple. + + """ + f = open("demo.txt", "w") + f.write("Contenu de notre fichier texte de démo e!") + f.close() + + +def read_file(): + """ + Lire dans un fichier texte très simple. + + """ + f = open("demo.txt", "r") + data = f.read() + f.close() + print(data) + + +if __name__ == "__main__": + write_file() + read_file() diff --git a/source/08-text-files/json/__init__.py b/source/08-text-files/json/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/08-text-files/json/demo.json b/source/08-text-files/json/demo.json new file mode 100644 index 0000000..080288e --- /dev/null +++ b/source/08-text-files/json/demo.json @@ -0,0 +1,25 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": [ + "GML", + "XML" + ] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/source/08-text-files/json/jsondecode.py b/source/08-text-files/json/jsondecode.py new file mode 100644 index 0000000..1fabfa5 --- /dev/null +++ b/source/08-text-files/json/jsondecode.py @@ -0,0 +1,12 @@ +import json +from os.path import dirname, join + +# N'exécute le code que si vous avez spécifiquement exécuté ce module python +if __name__ == "__main__": + saisie = input("Saisissez un truc") + current_folder = dirname(__file__) + # Ouvre le fichier demo.json en lecture + f = open(join(current_folder, "demo.json"), "r", encoding="utf-8") + data = json.load(f) # Va manipuler le descripteur de fichier et renvoyer les données converties + print(type(data)) # Vérifier que le type de la donnée n'est plus juste du texte + f.close() diff --git a/source/08-text-files/json/jsonencode.py b/source/08-text-files/json/jsonencode.py new file mode 100644 index 0000000..d2e0518 --- /dev/null +++ b/source/08-text-files/json/jsonencode.py @@ -0,0 +1,26 @@ +from json import dumps + +# N'exécute le code que si vous avez spécifiquement exécuté ce module python +if __name__ == "__main__": + data = { + "users": [ + { + "name": "Jean", + "age": 25 + }, + { + "name": "Denis", + "age": 30 + }, + { + "name": "Alice", + "age": 35 + }, + { + "name": "Achour", + "age": 40 + } + ] + } + chaine = dumps(data) + print(type(chaine)) diff --git a/source/08-text-files/text-files/files/don-diego.txt b/source/08-text-files/text-files/files/don-diego.txt new file mode 100644 index 0000000..dcbf0b0 --- /dev/null +++ b/source/08-text-files/text-files/files/don-diego.txt @@ -0,0 +1,25 @@ +DON DIÈGUE +Ô rage ! ô désespoir ! ô vieillesse ennemie ! +N’ai-je donc tant vécu que pour cette infamie ? +Et ne suis-je blanchi dans les travaux guerriers +Que pour voir en un jour flétrir tant de lauriers ? +Mon bras qu’avec respect tout l’Espagne admire, +Mon bras, qui tant de fois a sauvé cet empire, +Tant de fois affermi le trône de son roi, +Trahit donc ma querelle, et ne fait rien pour moi ? +Ô cruel souvenir de ma gloire passée ! +Œuvre de tant de jours en un jour effacée ! +Nouvelle dignité fatale à mon bonheur ! +Précipice élevé d’où tombe mon honneur ! +Faut-il de votre éclat voir triompher le comte, +Et mourir sans vengeance, ou vivre dans la honte ? +Comte, sois de mon prince à présent gouverneur ; +Ce haut rang n’admet point un homme sans honneur ; +Et ton jaloux orgueil par cet affront insigne +Malgré le choix du roi, m’en a su rendre indigne. +Et toi, de mes exploits glorieux instrument, +Mais d’un corps tout de glace inutile ornement, +Fer, jadis tant à craindre, et qui, dans cette offense, +M’as servi de parade, et non pas de défense, +Va, quitte désormais le derniers des humains, +Passe, pour me venger, en de meilleurs mains. diff --git a/source/08-text-files/text-files/source/fileread_classic.py b/source/08-text-files/text-files/source/fileread_classic.py new file mode 100644 index 0000000..e421ee4 --- /dev/null +++ b/source/08-text-files/text-files/source/fileread_classic.py @@ -0,0 +1,18 @@ +""" +Base file reading example. + +This example uses: +- classic open/close of file +- while loop with walrus operator (Python 3.8). + +""" +if __name__ == '__main__': + file = open("../files/don-diego.txt", "r", encoding="utf-8") + # Read the file contents line by line using the walrus operator + # (introduced in Python 3.8) + # While the line read is not empty, you're not at the end of file. + while line := file.readline().strip(): + # Lines contain caret return. Using `.strip()` + # removes spaces and caret returns at the start and end. + print(f"{line}") + file.close() diff --git a/source/08-text-files/text-files/source/fileread_iterator.py b/source/08-text-files/text-files/source/fileread_iterator.py new file mode 100644 index 0000000..a64cba5 --- /dev/null +++ b/source/08-text-files/text-files/source/fileread_iterator.py @@ -0,0 +1,16 @@ +""" +Base file reading example. + +This example uses: +- context manager (with ... as) +- iterator (for ... in object). + +""" +if __name__ == '__main__': + with open("../files/don-diego.txt", "r", encoding="utf-8") as file: + # Read the file contents line by line + for count, line in enumerate(file): + # Lines contain caret return. Using `strip` + # removes spaces and caret returns at the start and end + # of the string. + print(f"{count} : {line.strip()}") diff --git a/source/08-text-files/xml/__init__.py b/source/08-text-files/xml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/08-text-files/xml/demo.xml b/source/08-text-files/xml/demo.xml new file mode 100644 index 0000000..843aabf --- /dev/null +++ b/source/08-text-files/xml/demo.xml @@ -0,0 +1,27 @@ + + + + Zorro + Danseur + + + Hulk + Footballeur + + + Zidane + Star + + + Beans + Epicier + + + Batman + Veterinaire + + + Spiderman + Veterinaire + + diff --git a/source/08-text-files/xml/xmldecode.py b/source/08-text-files/xml/xmldecode.py new file mode 100644 index 0000000..e75f988 --- /dev/null +++ b/source/08-text-files/xml/xmldecode.py @@ -0,0 +1,51 @@ +from typing import List + +from lxml import etree + +if __name__ == "__main__": + # Balise principale + base = etree.Element("FastDMU", {"version": "2.0"}) + # Balise Search system + root = etree.Element("SearchSystem") + # Deux champs pour Search System + root_title = etree.Element("Title") + root_mode = etree.Element("Mode") + root_title.text = "01" + root_mode.text = "AssembliesOnly" + root.append(root_title) + root.append(root_mode) + + # Liste des items à ajouter + items: List[str] = ["A", "B", "C"] + for item in items: + # Création des éléments + search_item = etree.Element("SearchItem") + item_mode = etree.Element("Mode") + item_type = etree.Element("Type") + item_value = etree.Element("Value") + item_field = etree.Element("Field") + item_field_name = etree.Element("FieldName") + item_title = etree.Element("Title") + # Définition du texte + item_mode.text = "Add" + item_type.text = "Wildcard" + item_value.text = item + item_field.text = "PARTNUMBER" + item_field_name.text = "PARTNUMBER" + item_title.text = "Partnumber" + # Ajout des éléments au parent + search_item.append(item_mode) + search_item.append(item_type) + search_item.append(item_value) + search_item.append(item_field) + search_item.append(item_field_name) + search_item.append(item_title) + # Ajout du searchitem à la balise SearchSystem + root.append(search_item) + # Ajout de la balise SearchSystem à la balise FastDMU + base.append(root) + # J'aurais peut-être préféré faire ça avec BeautifulSoup4 + # Ou peut-être gagner du temps en convertissant du texte directement + # en éléments XML. + print(etree.tostring(base, pretty_print=True, xml_declaration=True, encoding="iso8859-1", + doctype="")) diff --git a/source/08-text-files/xml/xmlmake.py b/source/08-text-files/xml/xmlmake.py new file mode 100644 index 0000000..e69de29 diff --git a/source/08-text-files/xml/xmlread.py b/source/08-text-files/xml/xmlread.py new file mode 100644 index 0000000..02f526e --- /dev/null +++ b/source/08-text-files/xml/xmlread.py @@ -0,0 +1,17 @@ +# Installer d'abord lxml avec pip install lxml +from lxml import etree + +# Read content from XML file +with open("demo.xml", "rb") as file: + text = file.read() + +# Read structure into Element object +structure = etree.fromstring(text) +print(type(structure)) + +print(structure.text) +print(structure.attrib) +for child in structure: + print(child, type(child), child.attrib) + +print(structure.find("user")) diff --git a/source/09-sqlite/basic-table/source/database.sqlite3 b/source/09-sqlite/basic-table/source/database.sqlite3 new file mode 100644 index 0000000..cc9b72a Binary files /dev/null and b/source/09-sqlite/basic-table/source/database.sqlite3 differ diff --git a/source/09-sqlite/basic-table/source/sqlitedemo.py b/source/09-sqlite/basic-table/source/sqlitedemo.py new file mode 100644 index 0000000..5156f22 --- /dev/null +++ b/source/09-sqlite/basic-table/source/sqlitedemo.py @@ -0,0 +1,28 @@ +import sqlite3 + +if __name__ == "__main__": + # Il existe dans Python une API unifiée, où les mêmes opérations + # s'effectuent avec les mêmes fonctions et méthodes, quelle que + # soit la base de données relationnelle SQL à laquelle on accède. + # Pour SQLite en l'occurrence, la méthode `.connect` ne prend qu'un seul + # paramètre, le nom de fichier, car SQLite est une base de données + # embarquée sans sécurité et n'a donc pas besoin de mot de passe ou de nom + # d'utilisateur. + connection = sqlite3.connect("database.sqlite3", isolation_level=None) + # Ici on crée une nouvelle table dans notre base de données si elle n'existe pas déjà. + # Cette fonction de la base de données renvoie un seul résultat pour dire que tout + # est OK. + connection.execute("CREATE TABLE IF NOT EXISTS person (nom varchar(30), prenom varchar(20), age int)") + # Insérer quelques nouvelles lignes de données dans notre nouvelle table. + connection.execute("INSERT INTO person VALUES ('Bouquet','Carole',62)") + connection.execute("INSERT INTO person VALUES ('Connery','Sean',85)") + connection.execute("INSERT INTO person VALUES ('Kotto','Yaphet',76)") + connection.execute("INSERT INTO person VALUES ('Zhang','Zhang',39)") + # Valider l'ajout et les nouvelles modifications en bloc (lorsque la base de données le permet) + connection.commit() + + values = connection.execute("SELECT * FROM person WHERE age > 50") + print(values.fetchall()) + # Ne pas oublier à la fin, lorsqu'on en a plus besoin, de fermer la connexion à la base (ou au fichier + # pour le cas de SQLite). + connection.close() diff --git a/source/10-graphical-ui/gui/__init__.py b/source/10-graphical-ui/gui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/10-graphical-ui/gui/basecontrols.py b/source/10-graphical-ui/gui/basecontrols.py new file mode 100644 index 0000000..9b8a4e1 --- /dev/null +++ b/source/10-graphical-ui/gui/basecontrols.py @@ -0,0 +1,69 @@ +import sys + +from PySide6.QtGui import QIcon +from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QMenuBar, QMenu, QAction, \ + QMainWindow, QWidget + + +class Window(QMainWindow): + """ + Classe définissant notre fenêtre principale. + + """ + + def __init__(self, parent=None): + """ + Initialiser chaque nouvelle instance de notre fenêtre. + + Args: + parent: Widget qui va contenir notre boîte de dialogue. + + """ + super().__init__(parent=parent) + self.setWindowTitle("Ma nouvelle fenêtre") + # Create widgets + self.icon = QIcon.fromTheme("scanner") + self.basewidget = QWidget(self) + self.edit = QLineEdit("Zone de texte") + self.button = QPushButton("Appuyez ici !") + self.menubar = QMenuBar(self) + self.menu = QMenu(self.menubar, title="Élément de menu principal") + self.menuentry = QAction(QIcon.fromTheme("network-wired"), "&Action") + self.menu.addAction(self.menuentry) + self.menubar.addAction(self.menu.menuAction()) + # Insérer un objet de mise en page dans notre fenêtre, + # et y ajouter nos champ de texte et bouton + self.setCentralWidget(self.basewidget) + layout = QVBoxLayout(self) + self.basewidget.setLayout(layout) + self.setMenuBar(self.menubar) + layout.addWidget(self.edit) + layout.addWidget(self.button) + self.setMinimumSize(640, 128) + # Connecter le clic du bouton à la méthode "validate_button" + self.button.clicked.connect(self.validate_button) + + def validate_button(self): + """ + On définit cette méthode pour répondre au clic sur un bouton. + + Il faut que l'on configure notre bouton pour que lorsqu'on clique + dessus, cette méthode soit exécutée. + + """ + print(f"Vous avez saisi {self.edit.text()}") + + +if __name__ == "__main__": + # Créer une instance qui définit une application Qt + # Via la variable "sys.argv", qui correspond aux arguments passés en ligne de commande + # dans une liste de chaînes (ex. python programme.py arg1 arg2 arg3) + # on peut configurer le comportement de notre application... + # Également : notre application est un Singleton + application = QApplication(sys.argv) + # Ajouter notre boîte de dialogue + window = Window() + window.show() + # Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres + application.exec_() + sys.exit() diff --git a/source/10-graphical-ui/gui/basecreator.py b/source/10-graphical-ui/gui/basecreator.py new file mode 100644 index 0000000..6dc62ae --- /dev/null +++ b/source/10-graphical-ui/gui/basecreator.py @@ -0,0 +1,27 @@ +import sys + +from PySide6.QtCore import QFile, QObject + +QObject + +# Exemple avec QT Designer +if __name__ == "__main__": + # Créer une instance qui définit une application Qt + # Via la variable "sys.argv", qui correspond aux arguments en ligne de commande + # on peut configurer le comportement de notre application... + # Également : notre application est un Singleton + application = QApplication(sys.argv) + # Utiliser Qt pour ouvrir le fichier Qt Designer qu'on a créé + file = QFile("files/base-ui.ui") + file.open(QFile.ReadOnly) + # Utiliser une classe de Qt qui est capable de créer des interfaces depuis des fichiers + loader = QUiLoader() + window = loader.load(file) + file.close() + # Ici on teste que l'on a bien accès aux variables membres du fichier qu'on a chargé + window.lineEdit: QLineEdit = window.lineEdit + window.lineEdit.setText("Bonjour les amis") + # Afficher notre fenêtre chargée + window.show() + # Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres + sys.exit(application.exec_()) diff --git a/source/10-graphical-ui/gui/basedialog.py b/source/10-graphical-ui/gui/basedialog.py new file mode 100644 index 0000000..16d7206 --- /dev/null +++ b/source/10-graphical-ui/gui/basedialog.py @@ -0,0 +1,34 @@ +import sys + +from PySide2.QtWidgets import QDialog, QApplication + + +class Dialog(QDialog): + """ + Classe définissant notre fenêtre principale. + + """ + + def __init__(self, parent=None): + """ + Initialiser chaque nouvelle instance de notre fenêtre. + + Args: + parent: Widget qui va contenir notre boîte de dialogue. + + """ + super().__init__(parent=parent) + self.setWindowTitle("Ma nouvelle fenêtre") + + +if __name__ == "__main__": + # Créer une instance qui définit une application Qt + # Via la variable "sys.argv", qui correspond aux arguments en ligne de commande + # on peut configurer le comportement de notre application... + # Également : notre application est un Singleton + application = QApplication(sys.argv) + # Ajouter notre boîte de dialogue + dialog = Dialog() + dialog.show() + # Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres + sys.exit(application.exec_()) diff --git a/source/10-graphical-ui/gui/files/base-ui.ui b/source/10-graphical-ui/gui/files/base-ui.ui new file mode 100644 index 0000000..59a7edb --- /dev/null +++ b/source/10-graphical-ui/gui/files/base-ui.ui @@ -0,0 +1,91 @@ + + + MainWindow + + + + 0 + 0 + 575 + 317 + + + + MainWindow + + + + + + + QLayout::SetMinimumSize + + + + + + + + PushButton + + + + + + + + + + + + + + 0 + 0 + 575 + 31 + + + + + Menu principal + + + + + + + + + + + + + .. + + + Action 1 + + + + + + .. + + + Action 2 + + + + + + .. + + + Action 3 + + + + + + diff --git a/source/10-graphical-ui/gui/files/python.png b/source/10-graphical-ui/gui/files/python.png new file mode 100644 index 0000000..2f4a026 Binary files /dev/null and b/source/10-graphical-ui/gui/files/python.png differ diff --git a/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/form.ui b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/form.ui new file mode 100644 index 0000000..f03cd94 --- /dev/null +++ b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/form.ui @@ -0,0 +1,22 @@ + + + Window + + + + 0 + 0 + 800 + 600 + + + + Window + + + + + + + + diff --git a/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.py b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.py new file mode 100644 index 0000000..e2424a7 --- /dev/null +++ b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.py @@ -0,0 +1,28 @@ +# This Python file uses the following encoding: utf-8 +import sys +import os + + +from PySide2.QtWidgets import QApplication, QMainWindow +from PySide2.QtCore import QFile +from PySide2.QtUiTools import QUiLoader + + +class Window(QMainWindow): + def __init__(self): + super(Window, self).__init__() + self.load_ui() + + def load_ui(self): + loader = QUiLoader() + path = os.path.join(os.path.dirname(__file__), "form.ui") + ui_file = QFile(path) + ui_file.open(QFile.ReadOnly) + loader.load(ui_file, self) + ui_file.close() + +if __name__ == "__main__": + app = QApplication([]) + widget = Window() + widget.show() + sys.exit(app.exec_()) diff --git a/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject new file mode 100644 index 0000000..51ec4a5 --- /dev/null +++ b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "form.ui"] +} diff --git a/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject.user b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject.user new file mode 100644 index 0000000..089446d --- /dev/null +++ b/source/10-graphical-ui/gui/files/qtcreatordemo/basewindow/main.pyproject.user @@ -0,0 +1,196 @@ + + + + + + EnvironmentId + {f52a1091-6a1a-4c8e-9bfd-fca585155f33} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + true + true + true + + + 0 + true + + true + Builtin.Questionable + + true + true + Builtin.DefaultTidyAndClazy + 6 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {d044ec2e-da82-4493-a678-1f0961b658b1} + -1 + 0 + 0 + 0 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + main + PythonEditor.RunConfiguration./home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py + /home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py + {9e6235fb-9067-40a7-be7d-a5b33f406c75} + /home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow/main.py + false + true + false + true + /home/steve/Code/python/initiation/source/gui/files/qtcreatordemo/basewindow + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/source/10-graphical-ui/gui/fileselector.py b/source/10-graphical-ui/gui/fileselector.py new file mode 100644 index 0000000..855c200 --- /dev/null +++ b/source/10-graphical-ui/gui/fileselector.py @@ -0,0 +1,20 @@ +""" +Example code to select file using a file dialog. + +Needs a Qt Application object and then a File dialog object. +The `getOpenFileName()` method on the file dialog object opens +a dialog for loading a single file. It returns a tuple, containing +the selected file name (str) and the filter (str). +If no file was selected (cancelled), you get empty strings in the tuple. +""" +from PySide6.QtWidgets import QFileDialog, QApplication + +application = QApplication() +# You don't need application.exec() here because the method blocks the python script execution. +dialog = QFileDialog(directory="/home/steve", caption="Sélectionnez un fichier", filter="Text files (*.txt);; All files (*.*)") +selection: tuple[str, str] = dialog.getOpenFileName() +print(selection) + +with open("/home/steve/Code/training/python/beginner/documentation/12-logging.md", "r") as file: + lines = file.readlines() +print(lines) diff --git a/source/10-graphical-ui/gui/menucontrols.py b/source/10-graphical-ui/gui/menucontrols.py new file mode 100644 index 0000000..54c2d6d --- /dev/null +++ b/source/10-graphical-ui/gui/menucontrols.py @@ -0,0 +1,86 @@ +import sys + +from PySide2.QtGui import QIcon +from PySide2.QtWidgets import QApplication, QLineEdit, QPushButton, QVBoxLayout, QAction, \ + QMainWindow, QWidget + + +class Dialog(QMainWindow): + """ + Classe définissant notre fenêtre principale. + + """ + + def __init__(self, parent=None): + """ + Initialiser chaque nouvelle instance de notre fenêtre. + + Args: + parent: Widget qui va contenir notre boîte de dialogue. + + """ + super().__init__(parent=parent) + # Changer le titre de la fenêtre et changer la position et taille + self.setWindowTitle("Ma nouvelle fenêtre") + self.setGeometry(50, 50, 640, 480) + # Définir l'icône pour la fenêtre + self.setWindowIcon(QIcon.fromTheme("exit")) + # On crée manuellement des contrôles dans notre fenêtre et des menus + self.edit = QLineEdit("Zone de texte") + self.button = QPushButton("Appuyez ici !") + self.menuentry1 = QAction(QIcon.fromTheme("exit"), "&Fin") + self.menuentry2 = QAction(QIcon.fromTheme("sleep"), "&Dodo") + self.filemenu = self.menuBar().addMenu("&File") + self.filemenu.addAction(self.menuentry1) + self.filemenu.addSeparator() + self.filemenu.addAction(self.menuentry2) + # Insérer un objet de mise en page dans notre fenêtre, + # et y ajouter nos champ de texte et bouton + frame = QWidget() + layout = QVBoxLayout() + layout.addWidget(self.edit) + layout.addWidget(self.button) + # Ajouter la mise en page au widget + frame.setLayout(layout) + # Définir le widget comme le contenu de la fenêtre + self.setCentralWidget(frame) + # Connecter le clic du bouton à la méthode "validate_button" + self.button.clicked.connect(self.button_clicked) + # Connecter la validation du menu1 à la même méthode + self.menuentry1.triggered.connect(self.button_clicked) + # Connecter la modification du champ de texte à une méthode + self.edit.textEdited.connect(self.text_modified) + + def button_clicked(self): + """ + On définit cette méthode pour répondre au clic sur un bouton. + + Il faut que l'on configure notre bouton pour que lorsqu'on clique + dessus, cette méthode soit exécutée. + + """ + print(f"Vous avez saisi {self.edit.text()}") + + def text_modified(self): + """ + On définit cette méthode pour répondre à la modification du champ texte. + + Cette méthode n'est pas spécifique à Qt, c'est juste qu'on peut lier + des événements de contrôles Qt à des fonctions arbitraires. Et on + va lier l'édition du champ de texte à cette méthode-ci. + + """ + print(f"{self.edit.text()}") + + +if __name__ == "__main__": + # Créer une instance qui définit une application Qt + # Via la variable "sys.argv", qui correspond aux arguments en ligne de commande + # on peut configurer le comportement de notre application... + # Également : notre application est un Singleton + application = QApplication(sys.argv) + # Ajouter notre boîte de dialogue + dialog = Dialog() + dialog.show() + # Lancer la boucle Qt, qui ferme le programme quand on ferme toutes les fenêtres + sys.exit(application.exec_()) diff --git a/source/12-logging/logs/__init__.py b/source/12-logging/logs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/12-logging/logs/base.py b/source/12-logging/logs/base.py new file mode 100644 index 0000000..77f034f --- /dev/null +++ b/source/12-logging/logs/base.py @@ -0,0 +1,45 @@ +import logging +import sys + + +def logging_without_formatting(): + """ + La base de la journalisation. + + """ + logger = logging.getLogger("noformat") + logger.debug("This is a debug message") + logger.info("This is an info message") + logger.warning("This is a warning message") + logger.error("This is an error message") + logger.critical("This is a critical message") + + +def logging_with_formatting(): + """ + Configurer un peu notre journalisation pour mettre en forme nos messages. + + """ + logger = logging.getLogger("withformat") + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + # Créer une nouvelle configuration qui sort les messages de journal dans la console + handler = logging.StreamHandler(sys.stdout) + # Configurer cet objet pour utiliser notre format + handler.setFormatter(formatter) + # Configurer le handler pour afficher aussi les messages DEBUG et INFO + handler.setLevel(logging.DEBUG) + # Assigner notre configuration à notre logger + # On doit faire tout ça parce qu'il n'y a pas de méthode + # pour facilement définir une chaîne de formatage pour un logger + logger.addHandler(handler) + logger.warning("Message d'avertissement") + + +if __name__ == "__main__": + # Par défaut, Python n'affiche des messages de journalisation + # que s'ils excèdent une certaine sévérité. + # Dans la plupart des langages, par défaut, c'est la sévérité + # WARNING (en-dessous, on n'indique généralement pas de problème) + # qui est la plus basse prise en compte + logging_without_formatting() + logging_with_formatting() diff --git a/source/12-logging/logs/files.py b/source/12-logging/logs/files.py new file mode 100644 index 0000000..80ab0e8 --- /dev/null +++ b/source/12-logging/logs/files.py @@ -0,0 +1,43 @@ +import logging + + +def logging_with_formatting(): + """ + Configurer un peu notre journalisation pour mettre en forme nos messages. + + Nous devons utiliser un logger et le configurer pour savoir comment afficher nos + messages. + + Un logger peut utiliser plusieurs handlers à la fois, et chacun a pour rôle + de transporter le message original vers une destination (fichier, console etc.) + + Les handlers sont configurés en deux étapes : d'abord on choisit le type de + handler (fichier, console, etc.), et ensuite on lui associe un "formateur" pour + savoir comment stocker le message. + + Notez : les loggers peuvent avoir un nom, et peuvent ainsi être retrouvés n'importe où + via leur nom pendant l'exécution de votre script, en utilisant la fonction `getLogger`. + + """ + logger = logging.getLogger("withformat") + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + # Créer une nouvelle configuration qui sort les messages de journal dans la console + handler = logging.FileHandler("demo.log") + # Configurer cet objet pour utiliser notre format + handler.setFormatter(formatter) + # Et accessoirement, changer le niveau minimal de sévérité + handler.setLevel(logging.INFO) + # Assigner notre configuration à notre logger + # On doit faire tout ça parce qu'il n'y a pas de méthode + # pour facilement définir une chaîne de formatage pour un logger + logger.addHandler(handler) + logger.warning("Message d'avertissement") + + +if __name__ == "__main__": + # Par défaut, Python n'affiche des messages de journalisation + # que s'ils excèdent une certaine sévérité. + # Dans la plupart des langages, par défaut, c'est la sévérité + # WARNING (en-dessous, on n'indique généralement pas de problème) + # qui est la plus basse prise en compte + logging_with_formatting() diff --git a/source/99-ansible-test/base.yaml b/source/99-ansible-test/base.yaml new file mode 100644 index 0000000..f452c01 --- /dev/null +++ b/source/99-ansible-test/base.yaml @@ -0,0 +1,7 @@ +- hosts: localhost + connection: local + gather_facts: yes + vars: + my_name: a_b_c + tasks: + - debug: msg={{ my_name|replace('_', '-') }} diff --git a/source/99-ansible-test/facts.json b/source/99-ansible-test/facts.json new file mode 100644 index 0000000..78e8d75 --- /dev/null +++ b/source/99-ansible-test/facts.json @@ -0,0 +1,683 @@ + { + "ansible_facts": { + "ansible_all_ipv4_addresses": [ + "172.17.0.1", + "192.168.31.36", + "192.168.31.165" + ], + "ansible_all_ipv6_addresses": [ + "fe80::9fb5:601b:d3e9:a68e" + ], + "ansible_apparmor": { + "status": "disabled" + }, + "ansible_architecture": "x86_64", + "ansible_bios_date": "09/12/2022", + "ansible_bios_vendor": "Dell Inc.", + "ansible_bios_version": "1.19.0", + "ansible_board_asset_tag": "NA", + "ansible_board_name": "00K2XV", + "ansible_board_serial": "NA", + "ansible_board_vendor": "Dell Inc.", + "ansible_board_version": "A00", + "ansible_chassis_asset_tag": "NA", + "ansible_chassis_serial": "NA", + "ansible_chassis_vendor": "Dell Inc.", + "ansible_chassis_version": "NA", + "ansible_cmdline": { + "BOOT_IMAGE": "/boot/vmlinuz-6.9-x86_64", + "apparmor": "0", + "fsck.mode": "skip", + "intel_pstate": "active", + "loglevel": "3", + "nvidia-drm.modeset": "1", + "quiet": true, + "ro": true, + "root": "UUID=ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8", + "splash": true, + "udev.log_level": "3", + "udev.log_priority": "1", + "vga": "current" + }, + "ansible_date_time": { + "date": "2024-07-11", + "day": "11", + "epoch": "1720705695", + "epoch_int": "1720705695", + "hour": "15", + "iso8601": "2024-07-11T13:48:15Z", + "iso8601_basic": "20240711T154815266191", + "iso8601_basic_short": "20240711T154815", + "iso8601_micro": "2024-07-11T13:48:15.266191Z", + "minute": "48", + "month": "07", + "second": "15", + "time": "15:48:15", + "tz": "CEST", + "tz_dst": "CEST", + "tz_offset": "+0200", + "weekday": "jeudi", + "weekday_number": "4", + "weeknumber": "28", + "year": "2024" + }, + "ansible_default_ipv4": { + "address": "192.168.31.36", + "alias": "eno2", + "broadcast": "192.168.31.255", + "gateway": "192.168.31.1", + "interface": "eno2", + "macaddress": "a4:bb:6d:ef:9d:84", + "mtu": 1500, + "netmask": "255.255.255.0", + "network": "192.168.31.0", + "prefix": "24", + "type": "ether" + }, + "ansible_default_ipv6": {}, + "ansible_device_links": { + "ids": { + "mmcblk0": [ + "mmc-00000_0x15cdb40e" + ], + "mmcblk0p1": [ + "mmc-00000_0x15cdb40e-part1" + ], + "nvme0n1": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1", + "nvme-eui.00000000000000018ce38e030035c0c1" + ], + "nvme0n1p1": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part1", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part1", + "nvme-eui.00000000000000018ce38e030035c0c1-part1" + ], + "nvme0n1p2": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part2", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part2", + "nvme-eui.00000000000000018ce38e030035c0c1-part2" + ], + "nvme0n1p3": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part3", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part3", + "nvme-eui.00000000000000018ce38e030035c0c1-part3" + ] + }, + "labels": { + "mmcblk0p1": [ + "CLEANED" + ] + }, + "masters": {}, + "uuids": { + "mmcblk0p1": [ + "588B-5CCE" + ], + "nvme0n1p1": [ + "7D05-E937" + ], + "nvme0n1p2": [ + "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8" + ], + "nvme0n1p3": [ + "d626c980-e737-484f-ab18-6324704f4d74" + ] + } + }, + "ansible_devices": { + "mmcblk0": { + "holders": [], + "host": "Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS5260 PCI Express Card Reader (rev 01)", + "links": { + "ids": [ + "mmc-00000_0x15cdb40e" + ], + "labels": [], + "masters": [], + "uuids": [] + }, + "model": null, + "partitions": { + "mmcblk0p1": { + "holders": [], + "links": { + "ids": [ + "mmc-00000_0x15cdb40e-part1" + ], + "labels": [ + "CLEANED" + ], + "masters": [], + "uuids": [ + "588B-5CCE" + ] + }, + "sectors": "125794304", + "sectorsize": 512, + "size": "59.98 GB", + "start": "32768", + "uuid": "588B-5CCE" + } + }, + "removable": "0", + "rotational": "0", + "sas_address": null, + "sas_device_handle": null, + "scheduler_mode": "mq-deadline", + "sectors": "125827072", + "sectorsize": "512", + "serial": "0x15cdb40e", + "size": "60.00 GB", + "support_discard": "4194304", + "vendor": null, + "virtual": 1 + }, + "nvme0n1": { + "holders": [], + "host": "Non-Volatile memory controller: Toshiba Corporation XG6 NVMe SSD Controller", + "links": { + "ids": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1", + "nvme-eui.00000000000000018ce38e030035c0c1" + ], + "labels": [], + "masters": [], + "uuids": [] + }, + "model": "KXG60ZNV512G NVMe KIOXIA 512GB", + "partitions": { + "nvme0n1p1": { + "holders": [], + "links": { + "ids": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part1", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part1", + "nvme-eui.00000000000000018ce38e030035c0c1-part1" + ], + "labels": [], + "masters": [], + "uuids": [ + "7D05-E937" + ] + }, + "sectors": "614400", + "sectorsize": 512, + "size": "300.00 MB", + "start": "4096", + "uuid": "7D05-E937" + }, + "nvme0n1p2": { + "holders": [], + "links": { + "ids": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part2", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part2", + "nvme-eui.00000000000000018ce38e030035c0c1-part2" + ], + "labels": [], + "masters": [], + "uuids": [ + "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8" + ] + }, + "sectors": "981133465", + "sectorsize": 512, + "size": "467.84 GB", + "start": "618496", + "uuid": "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8" + }, + "nvme0n1p3": { + "holders": [], + "links": { + "ids": [ + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L-part3", + "nvme-KXG60ZNV512G_NVMe_KIOXIA_512GB_40LA75CBK81L_1-part3", + "nvme-eui.00000000000000018ce38e030035c0c1-part3" + ], + "labels": [], + "masters": [], + "uuids": [ + "d626c980-e737-484f-ab18-6324704f4d74" + ] + }, + "sectors": "18454939", + "sectorsize": 512, + "size": "8.80 GB", + "start": "981751961", + "uuid": "d626c980-e737-484f-ab18-6324704f4d74" + } + }, + "removable": "0", + "rotational": "0", + "sas_address": null, + "sas_device_handle": null, + "scheduler_mode": "none", + "sectors": "1000215216", + "sectorsize": "512", + "serial": "40LA75CBK81L", + "size": "476.94 GB", + "support_discard": "512", + "vendor": null, + "virtual": 1 + } + }, + "ansible_distribution": "Archlinux", + "ansible_distribution_file_path": "/etc/arch-release", + "ansible_distribution_file_variety": "Archlinux", + "ansible_distribution_major_version": "24", + "ansible_distribution_release": "Wynsdey", + "ansible_distribution_version": "24.0.3", + "ansible_dns": { + "nameservers": [ + "192.168.31.1" + ], + "search": [ + "toulouse.dawan.fr" + ] + }, + "ansible_docker0": { + "active": false, + "device": "docker0", + "id": "8000.0242ec8e49bf", + "interfaces": [], + "ipv4": { + "address": "172.17.0.1", + "broadcast": "172.17.255.255", + "netmask": "255.255.0.0", + "network": "172.17.0.0", + "prefix": "16" + }, + "macaddress": "02:42:ec:8e:49:bf", + "mtu": 1500, + "promisc": false, + "speed": -1, + "stp": false, + "type": "bridge" + }, + "ansible_domain": "", + "ansible_effective_group_id": 1000, + "ansible_effective_user_id": 1000, + "ansible_eno2": { + "active": true, + "device": "eno2", + "ipv4": { + "address": "192.168.31.36", + "broadcast": "192.168.31.255", + "netmask": "255.255.255.0", + "network": "192.168.31.0", + "prefix": "24" + }, + "macaddress": "a4:bb:6d:ef:9d:84", + "module": "e1000e", + "mtu": 1500, + "pciid": "0000:00:1f.6", + "promisc": false, + "speed": 1000, + "type": "ether" + }, + "ansible_env": { + "AUTOJUMP_ERROR_PATH": "/home/steve/.local/share/autojump/errors.log", + "AUTOJUMP_SOURCED": "1", + "DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus", + "DEBUGINFOD_URLS": "https://debuginfod.archlinux.org ", + "DESKTOP_SESSION": "gnome", + "DESKTOP_STARTUP_ID": "gnome-shell/PyCharm Professional Edition/4132-3-skdell_TIME4966895", + "DISPLAY": ":1", + "EDITOR": "/usr/bin/micro", + "GDMSESSION": "gnome", + "GDM_LANG": "fr_FR.UTF-8", + "GIO_LAUNCHED_DESKTOP_FILE": "/home/steve/.local/share/applications/jetbrains-pycharm.desktop", + "GIO_LAUNCHED_DESKTOP_FILE_PID": "111302", + "GJS_DEBUG_OUTPUT": "stderr", + "GJS_DEBUG_TOPICS": "JS ERROR;JS LOG", + "GNUPGHOME": "/home/steve/.local/share/gnupg", + "GTK3_MODULES": "xapp-gtk3-module", + "HOME": "/home/steve", + "INVOCATION_ID": "0dadf7989e324b038ebd153569baec41", + "IPYTHONDIR": "/home/steve/.local/share/ipython", + "JEDITERM_SOURCE_ARGS": "", + "JOURNAL_STREAM": "9:12207", + "LANG": "fr_FR.UTF-8", + "LOGNAME": "steve", + "MAIL": "/var/spool/mail/steve", + "MANAGERPID": "3884", + "MEMORY_PRESSURE_WATCH": "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/session.slice/org.gnome.Shell@x11.service/memory.pressure", + "MEMORY_PRESSURE_WRITE": "c29tZSAyMDAwMDAgMjAwMDAwMAA=", + "MOTD_SHOWN": "pam", + "NODE_PATH": "/home/steve/.local/share/node", + "NODE_REPL_HISTORY": "/home/steve/.cache/node_history", + "OMF_CONFIG": "/home/steve/.config/omf", + "OMF_PATH": "/home/steve/.local/share/omf", + "PATH": "/home/steve/Code/python/environments/ansible/bin:/home/steve/.pyenv/shims:/home/steve/.local/bin:~/.pyenv/bin:/usr/local/bin:~/.pyenv/bin:/usr/bin:~/.pyenv/bin:/usr/local/sbin:~/.pyenv/bin:/var/lib/flatpak/exports/bin:~/.pyenv/bin:/usr/lib/jvm/default/bin:~/.pyenv/bin:/usr/bin/site_perl:~/.pyenv/bin:/usr/bin/vendor_perl:~/.pyenv/bin:/usr/bin/core_perl:~/.pyenv/bin", + "PWD": "/home/steve/Code/training/python/beginner/source/99-ansible-test", + "PYENV_SHELL": "fish", + "QT_AUTO_SCREEN_SCALE_FACTOR": "1", + "QT_IM_MODULE": "ibus", + "QT_STYLE_OVERRIDE": "qt6ct", + "SESSION_MANAGER": "local/skdell:@/tmp/.ICE-unix/4103,unix/skdell:/tmp/.ICE-unix/4103", + "SHELL": "/usr/bin/fish", + "SHLVL": "2", + "SSH_AUTH_SOCK": "/run/user/1000/gcr/ssh", + "SYSTEMD_EXEC_PID": "4132", + "TERM": "xterm-256color", + "TERMINAL_EMULATOR": "JetBrains-JediTerm", + "TERM_SESSION_ID": "017aefd1-69ab-4952-8dd0-0333292a71e6", + "USER": "steve", + "USERNAME": "steve", + "VIRTUAL_ENV": "/home/steve/Code/python/environments/ansible", + "VIRTUAL_ENV_DISABLE_PROMPT": "1", + "VIRTUAL_ENV_PROMPT": "ansible", + "VSCODE_EXTENSIONS": "/home/steve/.local/share/vscode/extensions", + "WINDOWPATH": "2", + "WINEPREFIX": "/home/steve/.local/share/wine", + "XAUTHORITY": "/run/user/1000/gdm/Xauthority", + "XDG_ACTIVATION_TOKEN": "gnome-shell/PyCharm Professional Edition/4132-3-skdell_TIME4966895", + "XDG_CURRENT_DESKTOP": "GNOME", + "XDG_DATA_DIRS": "/home/steve/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share/:/usr/share/", + "XDG_MENU_PREFIX": "gnome-", + "XDG_RUNTIME_DIR": "/run/user/1000", + "XDG_SESSION_CLASS": "user", + "XDG_SESSION_DESKTOP": "gnome", + "XDG_SESSION_TYPE": "x11", + "XMODIFIERS": "@im=ibus", + "_": "/home/steve/Code/python/environments/ansible/bin/python", + "_OLD_VIRTUAL_PATH": "/home/steve/.pyenv/shims:/home/steve/.local/bin:~/.pyenv/bin:/usr/local/bin:~/.pyenv/bin:/usr/bin:~/.pyenv/bin:/usr/local/sbin:~/.pyenv/bin:/var/lib/flatpak/exports/bin:~/.pyenv/bin:/usr/lib/jvm/default/bin:~/.pyenv/bin:/usr/bin/site_perl:~/.pyenv/bin:/usr/bin/vendor_perl:~/.pyenv/bin:/usr/bin/core_perl:~/.pyenv/bin" + }, + "ansible_fibre_channel_wwn": [], + "ansible_fips": false, + "ansible_form_factor": "Notebook", + "ansible_fqdn": "skdell", + "ansible_hostname": "skdell", + "ansible_hostnqn": "", + "ansible_interfaces": [ + "lo", + "eno2", + "docker0", + "wlo1" + ], + "ansible_is_chroot": false, + "ansible_iscsi_iqn": "", + "ansible_kernel": "6.9.8-1-MANJARO", + "ansible_kernel_version": "#1 SMP PREEMPT_DYNAMIC Sat Jul 6 05:51:22 UTC 2024", + "ansible_lo": { + "active": true, + "device": "lo", + "ipv4": { + "address": "127.0.0.1", + "broadcast": "", + "netmask": "255.0.0.0", + "network": "127.0.0.0", + "prefix": "8" + }, + "ipv6": [ + { + "address": "::1", + "prefix": "128", + "scope": "host" + } + ], + "mtu": 65536, + "promisc": false, + "type": "loopback" + }, + "ansible_loadavg": { + "15m": 2.26904296875, + "1m": 2.1435546875, + "5m": 2.521484375 + }, + "ansible_local": {}, + "ansible_locally_reachable_ips": { + "ipv4": [ + "127.0.0.0/8", + "127.0.0.1", + "172.17.0.1", + "192.168.31.36", + "192.168.31.165" + ], + "ipv6": [ + "::1", + "fe80::9fb5:601b:d3e9:a68e" + ] + }, + "ansible_lsb": { + "codename": "Wynsdey", + "description": "Manjaro Linux", + "id": "ManjaroLinux", + "major_release": "24", + "release": "24.0.3" + }, + "ansible_lvm": "N/A", + "ansible_machine": "x86_64", + "ansible_machine_id": "a1c1d092794f4871a548c9775dd5337c", + "ansible_memfree_mb": 389, + "ansible_memory_mb": { + "nocache": { + "free": 11746, + "used": 20055 + }, + "real": { + "free": 389, + "total": 31801, + "used": 31412 + }, + "swap": { + "cached": 0, + "free": 9010, + "total": 9011, + "used": 1 + } + }, + "ansible_memtotal_mb": 31801, + "ansible_mounts": [ + { + "block_available": 42256932, + "block_size": 4096, + "block_total": 120436125, + "block_used": 78179193, + "device": "/dev/nvme0n1p2", + "dump": 0, + "fstype": "ext4", + "inode_available": 28418923, + "inode_total": 30662656, + "inode_used": 2243733, + "mount": "/", + "options": "rw,noatime", + "passno": 0, + "size_available": 173084393472, + "size_total": 493306368000, + "uuid": "ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8" + }, + { + "block_available": 57918, + "block_size": 4096, + "block_total": 76646, + "block_used": 18728, + "device": "/dev/nvme0n1p1", + "dump": 0, + "fstype": "vfat", + "inode_available": 0, + "inode_total": 0, + "inode_used": 0, + "mount": "/boot/efi", + "options": "rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro", + "passno": 0, + "size_available": 237232128, + "size_total": 313942016, + "uuid": "7D05-E937" + }, + { + "block_available": 1964168, + "block_size": 32768, + "block_total": 1965055, + "block_used": 887, + "device": "/dev/mmcblk0p1", + "dump": 0, + "fstype": "vfat", + "inode_available": 0, + "inode_total": 0, + "inode_used": 0, + "mount": "/run/media/steve/CLEANED", + "options": "rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro", + "passno": 0, + "size_available": 64361857024, + "size_total": 64390922240, + "uuid": "588B-5CCE" + } + ], + "ansible_nodename": "skdell", + "ansible_os_family": "Archlinux", + "ansible_pkg_mgr": "pacman", + "ansible_proc_cmdline": { + "BOOT_IMAGE": "/boot/vmlinuz-6.9-x86_64", + "apparmor": "0", + "fsck.mode": "skip", + "intel_pstate": "active", + "loglevel": "3", + "nvidia-drm.modeset": "1", + "quiet": true, + "ro": true, + "root": "UUID=ae7bbe2b-e356-4f63-bdf6-a6a3463bf1a8", + "splash": true, + "udev.log_level": "3", + "udev.log_priority": "1", + "vga": "current" + }, + "ansible_processor": [ + "0", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "1", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "2", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "3", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "4", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "5", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "6", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "7", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "8", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "9", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "10", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz", + "11", + "GenuineIntel", + "Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz" + ], + "ansible_processor_cores": 6, + "ansible_processor_count": 1, + "ansible_processor_nproc": 12, + "ansible_processor_threads_per_core": 2, + "ansible_processor_vcpus": 12, + "ansible_product_name": "Precision 7750", + "ansible_product_serial": "NA", + "ansible_product_uuid": "NA", + "ansible_product_version": "NA", + "ansible_python": { + "executable": "/home/steve/Code/python/environments/ansible/bin/python", + "has_sslcontext": true, + "type": "cpython", + "version": { + "major": 3, + "micro": 4, + "minor": 12, + "releaselevel": "final", + "serial": 0 + }, + "version_info": [ + 3, + 12, + 4, + "final", + 0 + ] + }, + "ansible_python_version": "3.12.4", + "ansible_real_group_id": 1000, + "ansible_real_user_id": 1000, + "ansible_selinux": { + "status": "Missing selinux Python library" + }, + "ansible_selinux_python_present": false, + "ansible_service_mgr": "systemd", + "ansible_ssh_host_key_dsa_public": "AAAAB3NzaC1kc3MAAACBAOLJ7UDNOsYU1QL6qk+fSxD8fZDG0miFVd1qcYusCRxCPJwEi7ClIcrTosPusubxC3Vvo7FtYqRpCjwmZaSiI+K+BmhkSK7LKN63XsHSAW+pK5Q5gnmARBrzTCF1pDm3uh/AYS0SISMbgc4+I7EXBKOJ94RQg1FliBpiNiv17zg5AAAAFQDU0YgWYQ55gfCr7ZehXDtm0axs4QAAAIEAlAfHG9dyqSmhAwS1s3mSFLTuG2MU8DruNCzX0dub7ObW8iQS4+FDahSdxCMY+PWwZEJ27SgAzWd5wCpAKFoFgoiOVeVCiRt7QyIkQHR4ENDRxEpzUEBvLLp31vQGwLf9mzHRSWxqfKX7h/ZoRpJpj4LTFcfvI0l1P82aszA11uMAAACAQZMqDsYbX2plxDw9ysbcyqP1hCh8WBwJik2wY/LCiV78JjljlVlkoat1HR1dJOQ+qKxA+EI6wEBhsrB9+waUVwdAJ4Aj1yQZnPUbDnFi+MwtAz0V9M6eNKi6SoxyBpaPPewKk24PF0igsyHPR+P+diQHO+momtiWK1SEO+bcnyQ=", + "ansible_ssh_host_key_dsa_public_keytype": "ssh-dss", + "ansible_ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHHzABDnum37ZKXtsmf1FJlIxkdCkj31DnFMlyM34MT52YUqstoXA6+AjbWQZ4q5nDP961ubepBjSXQIk4sNCkA=", + "ansible_ssh_host_key_ecdsa_public_keytype": "ecdsa-sha2-nistp256", + "ansible_ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIM54ly57FFU5JCOPN+G57sTJ4VfJuptq235TAfsFIy6v", + "ansible_ssh_host_key_ed25519_public_keytype": "ssh-ed25519", + "ansible_ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABgQDsgT8vRhNuBEmevRRUgsrtJfDXyqvaiShBn4UFUUv/2SS1qcme0UIEoBklQlbIAyUACa3+ZxAw08YXt9UuG/Sd/ykUfXtzsrDMKxQlb1VLFaXLpJ3wQYIbJi3gA3lrXfae+sKPOFl0c2+iuXF8B+zwKednu7qtHZbGsWxL3bRkmoQ1nBYcZwLU/s1EFU3/xRVAoo39aLYN3cB1RT7e2eWgPSB0Kv4emeGZHLjB3DNv36K8rwi8yYAXpiawbhxar5asiJ6S6/AchMofcbUo0wGX+/ArLTAysCu/rlUyA5+mh0hMFvqMc8mDHfg/elHf5K8PpphPKCixGpo5GfAzgeV7OjQOTibI2mKB6RAEYBK7/whNzcM0P2kt0xK2U84g3ppNdlOpqC1c3oOwiHxaHP2/BRkO2vntabcpLRjjWhm6hqMrBPgtRS67fChkrsW6hyQtuS9FGpyCDJpqsPhezve8KNy1A+OHwf4tPZTGflIMNnybYEe2B74Mdhn0aRWFP80=", + "ansible_ssh_host_key_rsa_public_keytype": "ssh-rsa", + "ansible_swapfree_mb": 9010, + "ansible_swaptotal_mb": 9011, + "ansible_system": "Linux", + "ansible_system_capabilities": [ + "" + ], + "ansible_system_capabilities_enforced": "True", + "ansible_system_vendor": "Dell Inc.", + "ansible_uptime_seconds": 29357, + "ansible_user_dir": "/home/steve", + "ansible_user_gecos": "Steve Kossouho", + "ansible_user_gid": 1000, + "ansible_user_id": "steve", + "ansible_user_shell": "/usr/bin/fish", + "ansible_user_uid": 1000, + "ansible_userspace_architecture": "x86_64", + "ansible_userspace_bits": "64", + "ansible_virtualization_role": "host", + "ansible_virtualization_tech_guest": [], + "ansible_virtualization_tech_host": [ + "kvm", + "virtualbox" + ], + "ansible_virtualization_type": "kvm", + "ansible_wlo1": { + "active": true, + "device": "wlo1", + "ipv4": { + "address": "192.168.31.165", + "broadcast": "192.168.31.255", + "netmask": "255.255.255.0", + "network": "192.168.31.0", + "prefix": "24" + }, + "ipv6": [ + { + "address": "fe80::9fb5:601b:d3e9:a68e", + "prefix": "64", + "scope": "link" + } + ], + "macaddress": "94:e7:0b:b6:cc:81", + "module": "iwlwifi", + "mtu": 1500, + "pciid": "0000:00:14.3", + "promisc": false, + "type": "ether" + }, + "gather_subset": [ + "all" + ], + "module_setup": true + }, + "changed": false +} diff --git a/source/TODO.txt b/source/TODO.txt new file mode 100644 index 0000000..85a64d9 --- /dev/null +++ b/source/TODO.txt @@ -0,0 +1,2 @@ +08 csv +09 sqlite mettre à jour l'exemple diff --git a/source/cardgame/card_application.py b/source/cardgame/card_application.py new file mode 100644 index 0000000..17d9e85 --- /dev/null +++ b/source/cardgame/card_application.py @@ -0,0 +1,44 @@ +""" +Fausse bataille avec les mauvaises règles. + +Ce n'est absolument pas comme ça qu'on joue à la bataille en +temps normal, mais je n'y avais pas joué depuis 30 ans. +Ceci étant, avec des règles simples, on arrive à un truc...exécutable. +""" +from source.cardgame.cards import Deck, Card + + +def main(): + full_deck: Deck = Deck(full=True, shuffled=True) + player1_deck: Deck = Deck() + player2_deck: Deck = Deck() + player1_score: int = 0 # dégueulasse + player2_score: int = 0 + # Choice was to distribute cards from one deck to player hands. + # Could be any strategy (and could be better). + while full_deck: + full_deck.pop_to(player1_deck) + full_deck.pop_to(player2_deck) + + while player1_deck: + # Show available cards to pick + selected_index: int = player1_deck.pick_input() + selected_card: Card = player1_deck.pop(selected_index) + opponent_card: Card = player2_deck.pop(0) + print(f"Player 1 plays {selected_card.full_name}") + print(f"Player 2 plays {opponent_card.full_name}") + if selected_card < opponent_card: + player2_score += 1 + print("Computer wins this round.") + elif selected_card > opponent_card: + player1_score += 1 + print("You won this round.") + + print(f"Player 1 final score: {player1_score}") + print(f"Player 2 final score: {player2_score}") + if player1_score == player2_score: + print("Pathetic!") + + +if __name__ == '__main__': + main() diff --git a/source/cardgame/cards.py b/source/cardgame/cards.py new file mode 100644 index 0000000..0e566b2 --- /dev/null +++ b/source/cardgame/cards.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from random import shuffle +from typing import Literal + +import inquirer + + +class Card: + """ + Standard poker card. + + Attributes: + value: + Absolute card value, between 2 and 14 (for the ace). + symbol (int): + Symbol of the card, as an integer. + 0 is hearts; 1 is diamonds, 2 is clubs and 3 is spades. + """ + SYMBOLS: dict[int, str] = {0: "Hearts", 1: "Diamonds", 2: "Clubs", 3: "Spades"} + VALUES: dict[int, str] = {11: "Jack", 12: "Queen", 13: "King", 14: "Ace"} + value: int = 2 + symbol: Literal[0, 1, 2, 3] = 0 + + def __init__(self, value: int, symbol: Literal[0, 1, 2, 3]): + self.symbol = symbol + self.value = value + + def __lt__(self, other: Card): + if isinstance(other, Card): + return self.value < other.value + raise TypeError(f"Can't compare {type(other)}") + + def __eq__(self, other: Card): + if isinstance(other, Card): + return self.value < other.value + raise TypeError(f"Can't compare {type(other)}") + + def __str__(self): + return f"{self.name} de {self.symbol_name}" + + @property + def name(self): + """Get the name of this card.""" + return self.VALUES.get(self.value, str(self.value)) + + @property + def symbol_name(self): + """Get the name of the symbol of this card.""" + return self.SYMBOLS.get(self.symbol, "N/A") + + @property + def full_name(self) -> str: + """Get the full name of this card, value and symbol.""" + return f"{self.name} of {self.symbol_name}" + + +class Deck: + """A deck of cards.""" + + _cards: list[Card] = None + + def __init__(self, full: bool = False, shuffled: bool = False): + """ + Initialize a deck with cards. + + Args: + full: If True, fill with all possible cards. + shuffled: If True, shuffle the content of the deck directly. + """ + self._cards = [] + if full is True: + for value in range(2, 15): + for symbol in range(0, 4): + self._cards.append(Card(value, symbol)) # noqa + if shuffled is True: + self.shuffle() + + def __bool__(self) -> bool: + """ + Tell if the deck is empty or not. + + Returns: + True: if not empty + False: otherwise. + """ + return bool(self._cards) + + def shuffle(self): + """Shuffle the deck so the cards are not ordered by value.""" + shuffle(self._cards) + + def pop_to(self, other: Deck) -> None: + """Remove last card from deck and add to another deck.""" + other._cards.append(self._cards.pop()) + + def pop(self, index: int) -> Card: + """Get card at index in deck and remove from the deck.""" + return self._cards.pop(index) + + def display_cards(self) -> None: + """Show available cards with their respective index in the deck.""" + for index, card in enumerate(self._cards): + print(f"{index:02}: {card.full_name}", end=" / ") + print() + + def pick_input(self) -> int: + """ + Ask the user to pick a card from the deck. + + Returns: + The selected index for a card. + """ + q = [inquirer.List("selection", message="Pick a card", choices=self.card_selection, default=0)] + return inquirer.prompt(q)["selection"] + + @property + def card_selection(self) -> list[tuple[str, int]]: + """ + Get available cards with their respective index in the deck. + + Returns: + A list of tuples, where each tuple contains two elements: + - The first element being the card name + - The second element being the card index + """ + return [(c.full_name, index) for index, c in enumerate(self._cards)] diff --git a/source/requirements.txt b/source/requirements.txt new file mode 100644 index 0000000..9d27753 --- /dev/null +++ b/source/requirements.txt @@ -0,0 +1,4 @@ +py2puml # conversion Python vers PlantUML +pdir2 # pretty printing avancé +ipython # console Python avancée +pyside6 # Qt Framework diff --git a/training/LICENSE b/training/LICENSE new file mode 100644 index 0000000..1e9fd8e --- /dev/null +++ b/training/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 sk-dwtoulouse + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/training/README.md b/training/README.md new file mode 100644 index 0000000..3c61564 --- /dev/null +++ b/training/README.md @@ -0,0 +1,5 @@ +# Exercices et démonstrations + +Démonstrations et exercices pour la formation d'initiation à Python. + +TODO: Thèmes possibles (Jeu de rôle ou une histoire de Toto) diff --git a/training/answers/02-language-basics/01-prints.adoc b/training/answers/02-language-basics/01-prints.adoc new file mode 100644 index 0000000..bfa9315 --- /dev/null +++ b/training/answers/02-language-basics/01-prints.adoc @@ -0,0 +1,17 @@ += Exercices + +== Exercice 1 + +[source, python] +---- +print("La rue Rostand,") +print(" se trouve au") +print("Feu à droite") +---- + +== Exercice 2 + +[source, python] +---- +print("Haut", "les", "cœurs", "!") +---- diff --git a/training/answers/02-language-basics/02-variables.adoc b/training/answers/02-language-basics/02-variables.adoc new file mode 100644 index 0000000..6ddc4b6 --- /dev/null +++ b/training/answers/02-language-basics/02-variables.adoc @@ -0,0 +1,65 @@ += Exercices + +== Exercice 1 + +[source, python] +---- +prenom = "Paul" +temperature = 24.8 +paul_age = 30 +print(prenom, temperature, paul_age) +---- + +== Exercice 2 + +[source, python] +---- +saisie = input("Saisissez du texte :") +print(saisie) +---- + +== Exercice 3 + +[source, python] +---- +val1 = 53 * 46 + 13 +val2 = 99 > 13 +val3 = "Bonjour " + "chef" +val4 = (59 * 62 + 13) / 6.5 +print(val1, val2, val3, val4) +---- + +== Exercice A1 + +[source, python] +---- +distance = 42195 +print(distance // 1000) # nombre de kilomètres +print(distance % 1000) # nombre de mètres restants +---- + +== Exercice A2 + +[source, python] +---- +weight = 4_502_177 +print(weight // 1000000, "tonnes") # combien de groupes de 1000000 de grammes +print((weight // 1000) % 1000) # combien de kilos restants, sans compter les tonnes +print(weight % 1000) # combien de grammes restants +---- + +== Exercice A3 + +[source, python] +---- +saisie1 = input("Premier nombre :") # attention, je vais récupérer du texte +saisie2 = input("Second nombre :") +saisie1 = float(saisie1) # convertir en flottant +saisie2 = float(saisie2) # convertir en flottant +if saisie1 > saisie2: + print(saisie1) +else: + print(saisie2) +# Autre possibilité intéressante +print(max(saisie1, saisie2)) +---- diff --git a/training/answers/02-language-basics/03-conditions.adoc b/training/answers/02-language-basics/03-conditions.adoc new file mode 100644 index 0000000..bf4d15b --- /dev/null +++ b/training/answers/02-language-basics/03-conditions.adoc @@ -0,0 +1,88 @@ += Exercices + +== Exercice 1 + +[source, python] +---- +roll = 5 +if roll > 4: + print("Lancer réussi !") +---- + +== Exercice 2 + +[source, python] +---- +text = "Bonjour" +if text == "bonjouR": + print("Bien le bonjour") +---- + +== Exercice 2B + +[source, python] +---- +text = "Bonjour" +if text == "Bonjour": + print("Bien le bonjour") +else: + print("Je ne comprends pas !") +---- + +== Exercice 3 + +[source, python] +---- +value = 7 +if value >= 9: + print("Élevé") +elif value >= 7: + print("Haut") +elif value >= 4: + print("Standard") +else: + print("Bas") +---- + +== Exercice A1 + +[source, python] +---- +a1 = 4 +a2 = 7 +if a1 > 5 and a2 < 6: + print("OK") +else: + print("Valeurs incorrectes") +---- + +== Exercice A2 + +[source, python] +---- +a1 = 5 +a2 = 5 +if a1 > 5 or a2 < 6: + print("Conditions suffisantes") +else: + print("Valeurs incorrectes") +---- + +== Exercice A3 + +[source, python] +---- +is_on = True +saisie = input("Saisissez une commande (Marche ou Arrêt) :") +if saisie == "Marche": + if is_on is False: + print("Allumage en cours…") + else: + print("Déjà allumé !") +elif saisie == "Arrêt": + if is_on: + print("Extinction…") + else: + print("Déjà éteint !") +---- + diff --git a/training/answers/02-language-basics/05-for-loop.adoc b/training/answers/02-language-basics/05-for-loop.adoc new file mode 100644 index 0000000..342188b --- /dev/null +++ b/training/answers/02-language-basics/05-for-loop.adoc @@ -0,0 +1,27 @@ += Exercices + +== Exercice 1 + +[source, python] +---- +for number in range(10): + print(number) +---- + +== Exercice 2 + +[source, python] +---- +for number in range(10): + if number % 2 == 0: # Est pair / reste 0 quand on fait la division entière + print(number) +---- + +== Exercice A1 + +[source, python] +---- +for item1 in range(10): + for item2 in range(item1): + print(item1, item2) +---- diff --git a/training/answers/02-language-basics/09-dictionaries.adoc b/training/answers/02-language-basics/09-dictionaries.adoc new file mode 100644 index 0000000..b2ec562 --- /dev/null +++ b/training/answers/02-language-basics/09-dictionaries.adoc @@ -0,0 +1,26 @@ += Exercices sur les dictionnaires + +''' + +== Exercice A1 : compréhension de dictionnaire + +*Rappel* : Convertir un dictionnaire en gardant les clés originales, +mais y associer comme valeurs uniquement les températures. + +[source,python] +---- +# Dictionnaire original +meteo = { + "Pau": (21.0, "Nuageux", 1015), + "Gap": (20.3, "Dégagé", 1019), + "Osny": (19.1, "Brouillard", 1015) +} +# Récupérer un dictionnaire dont les clés sont les noms de ville +# et dont les valeurs sont uniquement les températures : +# ici on conserve la clé, telle quelle, et comme chaque valeur +# associée aux clés est toujours un tuple dont le premier élément est la +# température, on peut s'y prendre ainsi : +converted = {key: meteo[key][0] for key in meteo} +# On affiche le résultat pour le vérifier +print(converted) +---- diff --git a/training/code/02-language-basics/01-prints/prints_01.py b/training/code/02-language-basics/01-prints/prints_01.py new file mode 100644 index 0000000..e4e3e0d --- /dev/null +++ b/training/code/02-language-basics/01-prints/prints_01.py @@ -0,0 +1,3 @@ +print("La rue Rostand,") +print(" se trouve au") +print("Feu à droite") diff --git a/training/code/02-language-basics/01-prints/prints_02.py b/training/code/02-language-basics/01-prints/prints_02.py new file mode 100644 index 0000000..6476384 --- /dev/null +++ b/training/code/02-language-basics/01-prints/prints_02.py @@ -0,0 +1 @@ +print("Hauts", "les", "cœurs", "!") diff --git a/training/code/02-language-basics/02-variables/variables_01.py b/training/code/02-language-basics/02-variables/variables_01.py new file mode 100644 index 0000000..d7fe087 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_01.py @@ -0,0 +1,11 @@ +prenom = "Paul" +temperature = 24.5 +age = 35 + +# Afficher les valeurs des variables +print(prenom) +print(temperature) +print(age) + +# Ou bien sur une seule ligne +print(prenom, temperature, age) diff --git a/training/code/02-language-basics/02-variables/variables_02.py b/training/code/02-language-basics/02-variables/variables_02.py new file mode 100644 index 0000000..a6890d6 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_02.py @@ -0,0 +1,4 @@ +saisie = input("Saisissez du texte :") + +# Afficher le texte qui a été récupéré de la fonction input +print(saisie) diff --git a/training/code/02-language-basics/02-variables/variables_03.py b/training/code/02-language-basics/02-variables/variables_03.py new file mode 100644 index 0000000..50e1ea6 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_03.py @@ -0,0 +1,10 @@ +result1 = 5 * 15 + 30 # Expression avec opérateurs arithmétiques +result2 = 9 > 4 # Stocke si 9 est supérieur à 4, donc `True` +result3 = "Chapi" + "Chapo" # concaténation +result4 = (59 * 62 + 13) / 6.5 # tester la valeur + +# Afficher les expressions +print(result1) +print(result2) +print(result3) +print(result4) diff --git a/training/code/02-language-basics/02-variables/variables_a1.py b/training/code/02-language-basics/02-variables/variables_a1.py new file mode 100644 index 0000000..e8b2f09 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_a1.py @@ -0,0 +1,7 @@ +distance = 42195 # distance en mètres +kilometers = distance // 1000 # nombre entier de paquets de 1 000 +meters = distance % 1000 # Reste après division entière par 1 000 + +# Affichage avec un peu de texte en plus. +print(kilometers, "km et", meters, "mètres.") + diff --git a/training/code/02-language-basics/02-variables/variables_a2.py b/training/code/02-language-basics/02-variables/variables_a2.py new file mode 100644 index 0000000..5a13860 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_a2.py @@ -0,0 +1,9 @@ +weight = 17_254_433 # Poids en grammes +tons = weight // 1_000_000 # Combien de paquets de 1 tonne +kilograms = (weight // 1_000) % 1_000 # Nombre de kilos restants sous la tonne +grams = weight % 1_000 # Nombre de grammes sous le kilo + +# Afficher les unités +print("Tonnes :", tons) +print("Kilogrammes :", kilograms) +print("Grammes :", grams) diff --git a/training/code/02-language-basics/02-variables/variables_a3.py b/training/code/02-language-basics/02-variables/variables_a3.py new file mode 100644 index 0000000..a7f4fc3 --- /dev/null +++ b/training/code/02-language-basics/02-variables/variables_a3.py @@ -0,0 +1,11 @@ +saisie1 = input("Entrez un premier nombre :") +saisie2 = input("Entrez un second nombre :") +# Convertir les deux entrées en entiers pour pouvoir les comparer +saisie1 = float(saisie1) +saisie2 = float(saisie2) + +# Afficher le nombre le plus grand, nécessite d'avoir vu les conditions +if saisie1 > saisie2: + print(saisie1, "est le plus grand nombre") +else: + print(saisie2, "est le plus grand nombre") diff --git a/training/code/02-language-basics/03-conditions/conditions_01.py b/training/code/02-language-basics/03-conditions/conditions_01.py new file mode 100644 index 0000000..6f1d760 --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_01.py @@ -0,0 +1,5 @@ +if __name__ == '__main__': + dice_roll = 5 + + if dice_roll > 4: + print("Lancer réussi !") diff --git a/training/code/02-language-basics/03-conditions/conditions_02.py b/training/code/02-language-basics/03-conditions/conditions_02.py new file mode 100644 index 0000000..e8be628 --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_02.py @@ -0,0 +1,5 @@ +if __name__ == '__main__': + text = "Bonjour" + # Ne devrait rien afficher puisque la chaîne ne correspond pas + if text == "bonjouR": + print("Bien le bonjour !") diff --git a/training/code/02-language-basics/03-conditions/conditions_02b.py b/training/code/02-language-basics/03-conditions/conditions_02b.py new file mode 100644 index 0000000..1c1d1a4 --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_02b.py @@ -0,0 +1,7 @@ +if __name__ == '__main__': + text = "Bonjour" + # Ne devrait rien afficher puisque la chaîne ne correspond pas + if text == "bonjouR": + print("Bien le bonjour !") + else: + print("Je n'ai pas compris !") diff --git a/training/code/02-language-basics/03-conditions/conditions_03.py b/training/code/02-language-basics/03-conditions/conditions_03.py new file mode 100644 index 0000000..8c7a99f --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_03.py @@ -0,0 +1,12 @@ +# Valeur de départ à changer au besoin pour tester +value = 8 + +# Tester plusieurs cas de figure s'excluant progressivement +if value >= 9: + print("Élevé") +elif value >= 7: + print("Haut") +elif value >= 4: + print("Standard") +else: + print("Bas") diff --git a/training/code/02-language-basics/03-conditions/conditions_a1.py b/training/code/02-language-basics/03-conditions/conditions_a1.py new file mode 100644 index 0000000..1217126 --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_a1.py @@ -0,0 +1,7 @@ +a1 = 6 +a2 = 5 + +if a1 > 5 and a2 < 6: + print("Conditions OK") +else: + print("Valeurs incorrectes") diff --git a/training/code/02-language-basics/03-conditions/conditions_a2.py b/training/code/02-language-basics/03-conditions/conditions_a2.py new file mode 100644 index 0000000..ee06d0c --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_a2.py @@ -0,0 +1,7 @@ +a1 = 6 +a2 = 5 + +if a1 > 5 or a2 < 6: + print("Conditions OK") +else: + print("Valeurs incorrectes") diff --git a/training/code/02-language-basics/03-conditions/conditions_a3.py b/training/code/02-language-basics/03-conditions/conditions_a3.py new file mode 100644 index 0000000..a299760 --- /dev/null +++ b/training/code/02-language-basics/03-conditions/conditions_a3.py @@ -0,0 +1,13 @@ +is_on = True +saisie = input("Saisissez une commande (Marche ou Arrêt) :") + +if saisie == "Marche": + if is_on is False: + print("Allumage en cours…") + else: + print("Déjà allumé !") +elif saisie == "Arrêt": + if is_on: + print("Extinction…") + else: + print("Déjà éteint !") diff --git a/training/code/02-language-basics/05-for-loop/forloop_01.py b/training/code/02-language-basics/05-for-loop/forloop_01.py new file mode 100644 index 0000000..c79192e --- /dev/null +++ b/training/code/02-language-basics/05-for-loop/forloop_01.py @@ -0,0 +1,2 @@ +for number in range(10): + print(number) diff --git a/training/code/02-language-basics/05-for-loop/forloop_02.py b/training/code/02-language-basics/05-for-loop/forloop_02.py new file mode 100644 index 0000000..c9d6886 --- /dev/null +++ b/training/code/02-language-basics/05-for-loop/forloop_02.py @@ -0,0 +1,3 @@ +for number in range(10): + if number % 2 == 0: # Est pair / reste 0 quand on fait la division entière + print(number) diff --git a/training/code/02-language-basics/05-for-loop/forloop_a1.py b/training/code/02-language-basics/05-for-loop/forloop_a1.py new file mode 100644 index 0000000..df2d518 --- /dev/null +++ b/training/code/02-language-basics/05-for-loop/forloop_a1.py @@ -0,0 +1,3 @@ +for item1 in range(10): + for item2 in range(item1): + print(item1, item2) diff --git a/training/code/02-language-basics/06-while-loop/whileloop_01.py b/training/code/02-language-basics/06-while-loop/whileloop_01.py new file mode 100644 index 0000000..78402d9 --- /dev/null +++ b/training/code/02-language-basics/06-while-loop/whileloop_01.py @@ -0,0 +1,5 @@ +number = 10 + +while number >= 0: + print(number) + number -= 1 # ou number = number - 1 diff --git a/training/code/02-language-basics/06-while-loop/whileloop_02.py b/training/code/02-language-basics/06-while-loop/whileloop_02.py new file mode 100644 index 0000000..cc16987 --- /dev/null +++ b/training/code/02-language-basics/06-while-loop/whileloop_02.py @@ -0,0 +1,6 @@ +iteration = 1 + +# Quitter la boucle avec Ctrl+C ou le bouton Stop de PyCharm +while True: + print("Itération", iteration) + iteration += 1 diff --git a/training/code/02-language-basics/06-while-loop/whileloop_03.py b/training/code/02-language-basics/06-while-loop/whileloop_03.py new file mode 100644 index 0000000..1e437b4 --- /dev/null +++ b/training/code/02-language-basics/06-while-loop/whileloop_03.py @@ -0,0 +1,6 @@ +iteration = 1 + +# Ne se lancera pas +while iteration > 10: + print("Itération", iteration) + iteration += 1 diff --git a/training/code/02-language-basics/06-while-loop/whileloop_a1.py b/training/code/02-language-basics/06-while-loop/whileloop_a1.py new file mode 100644 index 0000000..b0e8f9e --- /dev/null +++ b/training/code/02-language-basics/06-while-loop/whileloop_a1.py @@ -0,0 +1,45 @@ +# Possibilité 1 +left = 0 +right = 1 +new = 1 + +# Afficher les éléments successifs de la séquence avec une variable new +while new < 10_000: + new = left + right + print(new) + left = right + right = new + + +# Possibilité 2 +left = 0 +right = 1 +temp = None + +# Afficher les éléments successifs de la séquence avec une variable temporaire +while left + right < 10_000: + print(left + right) + temp = left + left = right + right = temp + right + + +# Possibilité 3 : algorithme +left = 0 +right = 1 + +# Afficher les éléments successifs de la séquence sans variable temporaire +while left + right < 10_000: + print(left + right) + right = left + right + left = right - left + + +# Possibilité 4 +left = 0 +right = 1 + +# Afficher les éléments successifs de la séquence via l'unpacking +while left + right < 10_000: + print(left + right) + left, right = (right, left + right) diff --git a/training/code/02-language-basics/07-lists/lists_01.py b/training/code/02-language-basics/07-lists/lists_01.py new file mode 100644 index 0000000..5b713a0 --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_01.py @@ -0,0 +1,7 @@ +even_numbers = [0, 2, 4, 6, 8, 10] +length = len(even_numbers) +# Afficher le dernier élément +print(even_numbers[length - 1]) +# Ajouter un élément et vérifier la modification +even_numbers.append(12) +print(even_numbers) diff --git a/training/code/02-language-basics/07-lists/lists_02.py b/training/code/02-language-basics/07-lists/lists_02.py new file mode 100644 index 0000000..3126692 --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_02.py @@ -0,0 +1,11 @@ +# Puissances de 2 de 0 à 6 +numbers = [1, 2, 4, 8, 16, 32, 64] + +# Retirer le nombre 8 (par sa valeur) +numbers.remove(8) + +# Ajouter la valeur 128 à la fin +numbers.append(128) + +# Affiher le résultat +print(numbers) diff --git a/training/code/02-language-basics/07-lists/lists_03.py b/training/code/02-language-basics/07-lists/lists_03.py new file mode 100644 index 0000000..6dee862 --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_03.py @@ -0,0 +1,8 @@ +# Liste contenant quelques valeurs +values = ["text", 3.14159, 16, True] + +# Afficher le dernier élément, quelle que soit la taille de la liste +print(values[-1]) + +# Afficher le premier élément en utilisant un index négatif +print(values[-len(values)]) diff --git a/training/code/02-language-basics/07-lists/lists_04.py b/training/code/02-language-basics/07-lists/lists_04.py new file mode 100644 index 0000000..af5261f --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_04.py @@ -0,0 +1,9 @@ +# Créer une liste de 6 nombres +numbers = [2, 3, 5, 8, 13, 21] + +# Afficher une liste contenant les 3 premiers éléments +print(numbers[0:3]) + +# Afficher une liste contenant les éléments de numbers du 2nd au dernier +print(numbers[1:]) + diff --git a/training/code/02-language-basics/07-lists/lists_05.py b/training/code/02-language-basics/07-lists/lists_05.py new file mode 100644 index 0000000..381aef8 --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_05.py @@ -0,0 +1,15 @@ +# Créer une liste de 6 nombres +numbers = [2, 3, 5, 8, 13, 21] + +# Afficher une liste contenant les 3 premiers éléments +print(numbers[0:3]) + +# Afficher une liste contenant les éléments de numbers du 2nd au dernier +print(numbers[1:]) + +# Afficher une liste contenant les éléments à l'envers +print(numbers[::-1]) + +# Afficher une liste contenant les éléments aux index pairs +print(numbers[0::2]) +print(numbers[::2]) diff --git a/training/code/02-language-basics/07-lists/lists_a1.py b/training/code/02-language-basics/07-lists/lists_a1.py new file mode 100644 index 0000000..e0e720d --- /dev/null +++ b/training/code/02-language-basics/07-lists/lists_a1.py @@ -0,0 +1,7 @@ +# Multiples de 3 +numbers = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45] + +# Parcourir la liste et afficher les éléments pairs +for number in numbers: + if (number % 2) == 0: + print(number) diff --git a/training/code/02-language-basics/08-sets/sets_01.py b/training/code/02-language-basics/08-sets/sets_01.py new file mode 100644 index 0000000..58df634 --- /dev/null +++ b/training/code/02-language-basics/08-sets/sets_01.py @@ -0,0 +1,15 @@ +# Créer des ensembles avec au moins deux valeurs en commun +set1 = {2, 4, 6, 8, 10} +set2 = {8, 10, 12, 14, 16} + +# Tenter d'ajouter une valeur déjà présente dans set1 +set1.add(6) + +# Afficher l'intersection des deux ensembles (valeurs en commun) +print(set1 & set2) # c'est pareil mais moins explicite +print(set1.intersection(set2)) # c'est pareil mais plus explicite + +# Afficher l'union des deux ensembles (toutes valeurs) +print(set1 | set2) +print(set1.union(set2)) + diff --git a/training/code/02-language-basics/08-sets/sets_02.py b/training/code/02-language-basics/08-sets/sets_02.py new file mode 100644 index 0000000..931c9d0 --- /dev/null +++ b/training/code/02-language-basics/08-sets/sets_02.py @@ -0,0 +1,7 @@ +# Déclarer une liste avec des doublons +duplicated = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7] +print(duplicated) + +# Créer un ensemble dédupliquant les éléments +deduplicated = set(duplicated) +print(deduplicated) diff --git a/training/code/02-language-basics/08-sets/sets_03.py b/training/code/02-language-basics/08-sets/sets_03.py new file mode 100644 index 0000000..c343773 --- /dev/null +++ b/training/code/02-language-basics/08-sets/sets_03.py @@ -0,0 +1,21 @@ +# Al et Kim sont inscrits sur un réseau social. Al a les amis suivants : +# +# - Josephine +# - Meghan +# - Amy +# - Bob +# +# Kim a les amis suivants : +# +# - Frank +# - Amy +# - Josephine +# - Susan +# +# Quels sont leurs amis en commun ? Écrivez un code qui représente et résout cet énoncé. +al_friends = {"Josephine", "Meghan", "Amy", "Bob"} +kim_friends = {"Frank", "Amy", "Josephine", "Susan"} + +# Afficher le bon résultat +print(al_friends & kim_friends) # Affichier l'intersection avec des opérateurs +print(al_friends.intersection(kim_friends)) # Affichier l'intersection plus explicite diff --git a/training/code/02-language-basics/08-sets/sets_04.py b/training/code/02-language-basics/08-sets/sets_04.py new file mode 100644 index 0000000..abf6d8f --- /dev/null +++ b/training/code/02-language-basics/08-sets/sets_04.py @@ -0,0 +1,5 @@ +# Partant du tuple suivant : +# `(1, 4, 6, 9, 1, 3, 6, 12, 2, 5, 7, 10, 3, 5, 2, 6, 4, 6, 1, 8, 5, 2, 3, 6)` +# - Affichez le nombre de valeurs différentes présentes dans le tuple. +sample = (1, 4, 6, 9, 1, 3, 6, 12, 2, 5, 7, 10, 3, 5, 2, 6, 4, 6, 1, 8, 5, 2, 3, 6) +print(len(set(sample))) diff --git a/training/code/02-language-basics/09-dictionaries/dictionaries_01.py b/training/code/02-language-basics/09-dictionaries/dictionaries_01.py new file mode 100644 index 0000000..7b12a28 --- /dev/null +++ b/training/code/02-language-basics/09-dictionaries/dictionaries_01.py @@ -0,0 +1,15 @@ +# - Écrivez un simple dictionnaire associant des noms à des âges : +# * Paul → 30 +# * Karim → 22 +# * Gina → 41 +# * Anna → 25 +# - Affichez l'âge de Gina +# - Ajoutez les associations suivantes : +# * Alina → 33 +# * Victor → 55 +# - Affichez le contenu du dictionnaire +ages = {"Paul": 30, "Karim": 22, "Gina": 41, "Anna": 25} +print(ages["Gina"]) +ages["Victor"] = 55 +ages["Alina"] = 33 +print(ages) diff --git a/training/code/02-language-basics/09-dictionaries/dictionaries_02.py b/training/code/02-language-basics/09-dictionaries/dictionaries_02.py new file mode 100644 index 0000000..dfaeac1 --- /dev/null +++ b/training/code/02-language-basics/09-dictionaries/dictionaries_02.py @@ -0,0 +1,18 @@ +# - Écrivez un simple dictionnaire associant des noms à des âges : +# * Paul → 30 +# * Karim → 22 +# * Gina → 41 +# * Anna → 25 +# - Affichez l'âge de Gina +# - Ajoutez les associations suivantes : +# * Alina → 33 +# * Victor → 55 +# - Affichez le contenu du dictionnaire +ages = {"Paul": 30, "Karim": 22, "Gina": 41, "Anna": 25} +ages["Victor"] = 55 +ages["Alina"] = 33 + +# Parcourir les clés et afficher la valeur associée +for name in ages: + print(name) + print(ages[name]) diff --git a/training/code/02-language-basics/09-dictionaries/dictionaries_03.py b/training/code/02-language-basics/09-dictionaries/dictionaries_03.py new file mode 100644 index 0000000..e69e74e --- /dev/null +++ b/training/code/02-language-basics/09-dictionaries/dictionaries_03.py @@ -0,0 +1,18 @@ +# - Écrivez un simple dictionnaire associant des noms à des âges : +# * Paul → 30 +# * Karim → 22 +# * Gina → 41 +# * Anna → 25 +# - Affichez l'âge de Gina +# - Ajoutez les associations suivantes : +# * Alina → 33 +# * Victor → 55 +# - Affichez le contenu du dictionnaire +ages = {"Paul": 30, "Karim": 22, "Gina": 41, "Anna": 25} +ages["Victor"] = 55 +ages["Alina"] = 33 + +# Parcourir les clés et afficher la valeur associée +for name, age in ages.items(): # Utiliser l'unpacking + print(name) + print(age) diff --git a/training/code/02-language-basics/09-dictionaries/dictionaries_a1.py b/training/code/02-language-basics/09-dictionaries/dictionaries_a1.py new file mode 100644 index 0000000..2a1af63 --- /dev/null +++ b/training/code/02-language-basics/09-dictionaries/dictionaries_a1.py @@ -0,0 +1,6 @@ +# Conditions météo +meteo = {"Pau": (21.0, "Nuageux", 1015), "Gap": (20.3, "Dégagé", 1019), "Osny": (19.1, "Brouillard", 1015)} + +# Conditions avec uniquement la température comme valeur associée +converted = {ville: meteo[ville][0] for ville in meteo} +print(converted) diff --git a/training/code/02-language-basics/09-dictionaries/dictionaries_a2.py b/training/code/02-language-basics/09-dictionaries/dictionaries_a2.py new file mode 100644 index 0000000..0830fb2 --- /dev/null +++ b/training/code/02-language-basics/09-dictionaries/dictionaries_a2.py @@ -0,0 +1,9 @@ +# Nombres pairs non divisibles par 5 +values = [x * 2 for x in range(50) if (x * 2) % 5 != 0] +print(values) + +# Liste de mots +words = ["matin", "le", "pour", "lapin", "carotte", "justesse", "ambroisie", "cuticule", "aube", "flanc", "flan"] +# Créer une liste avec uniquement les mots de plus de 4 lettres +short_words = [w for w in words if len(w) > 4] +print(short_words) diff --git a/training/code/04-functions/01-base/base_01.py b/training/code/04-functions/01-base/base_01.py new file mode 100644 index 0000000..a0cd616 --- /dev/null +++ b/training/code/04-functions/01-base/base_01.py @@ -0,0 +1,6 @@ +"""Déclaration de fonction simple.""" +def show_something(): + print("Something") + +# Exécuter la fonction +show_something() diff --git a/training/code/04-functions/01-base/base_02.py b/training/code/04-functions/01-base/base_02.py new file mode 100644 index 0000000..c024aac --- /dev/null +++ b/training/code/04-functions/01-base/base_02.py @@ -0,0 +1,8 @@ +"""Fonction simple retournant une constante.""" +def return_constant(): + print("Texte : 99") + return 99 # renvoie un nombre entier + +# Appeler la fonction et récupérer la valeur renvoyée +result = return_constant() +print(result) diff --git a/training/code/04-functions/01-base/base_03.py b/training/code/04-functions/01-base/base_03.py new file mode 100644 index 0000000..270deec --- /dev/null +++ b/training/code/04-functions/01-base/base_03.py @@ -0,0 +1,10 @@ +# Fonction produit +def product(x, y): + return x * y + + +# Tests d'appel de la fonction +print(product(10, 10)) +print(product(15, -15)) +print(product("hello ", 3)) +print(product([1, 2, 3], 2)) diff --git a/training/code/04-functions/01-base/base_04.py b/training/code/04-functions/01-base/base_04.py new file mode 100644 index 0000000..b050773 --- /dev/null +++ b/training/code/04-functions/01-base/base_04.py @@ -0,0 +1,22 @@ +"""Fonction qui calcule un quotient.""" + + +def quotient(numerator, denominator=1): + """ + Fonction de quotient. + + Renvoie `None` si l'argument `denominator` vaut 0. + + """ + try: + return numerator / denominator + except ZeroDivisionError: + # Si impossible d'évaluer l'expression ligne 4 + return None + + +# Tester plusieurs arguments pour la fonction +print(quotient(10, denominator=4)) +print(quotient(10, denominator=-1)) +print(quotient(1, denominator=0)) +print(quotient(5)) diff --git a/training/demos/08-text-files/lxml-demo/requirements.txt b/training/demos/08-text-files/lxml-demo/requirements.txt new file mode 100644 index 0000000..ab90481 --- /dev/null +++ b/training/demos/08-text-files/lxml-demo/requirements.txt @@ -0,0 +1 @@ +lxml diff --git a/training/demos/08-text-files/lxml-demo/source/files/catalog.xml b/training/demos/08-text-files/lxml-demo/source/files/catalog.xml new file mode 100644 index 0000000..2df1d5a --- /dev/null +++ b/training/demos/08-text-files/lxml-demo/source/files/catalog.xml @@ -0,0 +1,211 @@ + + + + Empire Burlesque + Bob Dylan + USA + Columbia + 10.90 + 1985 + + + Hide your heart + Bonnie Tyler + UK + CBS Records + 9.90 + 1988 + + + Greatest Hits + Dolly Parton + USA + RCA + 9.90 + 1982 + + + Still got the blues + Gary Moore + UK + Virgin records + 10.20 + 1990 + + + Eros + Eros Ramazzotti + EU + BMG + 9.90 + 1997 + + + One night only + Bee Gees + UK + Polydor + 10.90 + 1998 + + + Sylvias Mother + Dr.Hook + UK + CBS + 8.10 + 1973 + + + Maggie May + Rod Stewart + UK + Pickwick + 8.50 + 1990 + + + Romanza + Andrea Bocelli + EU + Polydor + 10.80 + 1996 + + + When a man loves a woman + Percy Sledge + USA + Atlantic + 8.70 + 1987 + + + Black angel + Savage Rose + EU + Mega + 10.90 + 1995 + + + 1999 Grammy Nominees + Many + USA + Grammy + 10.20 + 1999 + + + For the good times + Kenny Rogers + UK + Mucik Master + 8.70 + 1995 + + + Big Willie style + Will Smith + USA + Columbia + 9.90 + 1997 + + + Tupelo Honey + Van Morrison + UK + Polydor + 8.20 + 1971 + + + Soulsville + Jorn Hoel + Norway + WEA + 7.90 + 1996 + + + The very best of + Cat Stevens + UK + Island + 8.90 + 1990 + + + Stop + Sam Brown + UK + A and M + 8.90 + 1988 + + + Bridge of Spies + T'Pau + UK + Siren + 7.90 + 1987 + + + Private Dancer + Tina Turner + UK + Capitol + 8.90 + 1983 + + + Midt om natten + Kim Larsen + EU + Medley + 7.80 + 1983 + + + Pavarotti Gala Concert + Luciano Pavarotti + UK + DECCA + 9.90 + 1991 + + + The dock of the bay + Otis Redding + USA + Stax Records + 7.90 + 1968 + + + Picture book + Simply Red + EU + Elektra + 7.20 + 1985 + + + Red + The Communards + UK + London + 7.80 + 1987 + + + Unchain my heart + Joe Cocker + USA + EMI + 8.20 + 1987 + + \ No newline at end of file diff --git a/training/demos/08-text-files/lxml-demo/source/xml_read_demo.py b/training/demos/08-text-files/lxml-demo/source/xml_read_demo.py new file mode 100644 index 0000000..4358882 --- /dev/null +++ b/training/demos/08-text-files/lxml-demo/source/xml_read_demo.py @@ -0,0 +1,12 @@ +"""XML demo to parse a simple ctalog file.""" +from lxml import etree + + +tree = etree.parse(r"files/catalog.xml") # Get the whole document as the root element +# Récupérer les éléments de la racine CATALOG qui ont le nom CD +items = tree.xpath("//CATALOG/CD") + +for cd in items: + for attribute in cd: + print(attribute.tag, attribute.attrib) # afficher le nom et les attributs + print(attribute.text) diff --git a/training/demos/08-text-files/pandas-demo/requirements.txt b/training/demos/08-text-files/pandas-demo/requirements.txt new file mode 100644 index 0000000..95618ef --- /dev/null +++ b/training/demos/08-text-files/pandas-demo/requirements.txt @@ -0,0 +1,2 @@ +pandas==1.2.5 +xlrd>=1.0.0 diff --git a/training/demos/08-text-files/pandas-demo/source/csv_read_demo.py b/training/demos/08-text-files/pandas-demo/source/csv_read_demo.py new file mode 100644 index 0000000..8ec00ae --- /dev/null +++ b/training/demos/08-text-files/pandas-demo/source/csv_read_demo.py @@ -0,0 +1,26 @@ +""" +Pandas getting started script. + +Pandas introduction demo script for Python beginners. +Makes a few calls taken from the official docs to see what can be done +with Pandas. + +See Also: +https://pandas.pydata.org/docs/getting_started/comparison/comparison_with_sql.html + +""" +import pandas as pd + +if __name__ == "__main__": + # Read dataframe from CSV file + frame: pd.DataFrame = pd.read_csv("files/demo-file-985.csv") + # Get basic information on data + print(frame.dtypes) + + # Access, within column zero, to all rows + for row in frame.street: + print(row) + + # Make the equivalent to a SELECT WHERE query + # Get a frame where the price column is > 100,000 + print(frame[frame["price"] > 100000]) diff --git a/training/demos/08-text-files/pandas-demo/source/files/demo-file-1000.xls b/training/demos/08-text-files/pandas-demo/source/files/demo-file-1000.xls new file mode 100644 index 0000000..28b1ae2 Binary files /dev/null and b/training/demos/08-text-files/pandas-demo/source/files/demo-file-1000.xls differ diff --git a/training/demos/08-text-files/pandas-demo/source/files/demo-file-985.csv b/training/demos/08-text-files/pandas-demo/source/files/demo-file-985.csv new file mode 100644 index 0000000..c8a89ed --- /dev/null +++ b/training/demos/08-text-files/pandas-demo/source/files/demo-file-985.csv @@ -0,0 +1 @@ +street,city,zip,state,beds,baths,sq__ft,type,sale_date,price,latitude,longitude 3526 HIGH ST,SACRAMENTO,95838,CA,2,1,836,Residential,Wed May 21 00:00:00 EDT 2008,59222,38.631913,-121.434879 51 OMAHA CT,SACRAMENTO,95823,CA,3,1,1167,Residential,Wed May 21 00:00:00 EDT 2008,68212,38.478902,-121.431028 2796 BRANCH ST,SACRAMENTO,95815,CA,2,1,796,Residential,Wed May 21 00:00:00 EDT 2008,68880,38.618305,-121.443839 2805 JANETTE WAY,SACRAMENTO,95815,CA,2,1,852,Residential,Wed May 21 00:00:00 EDT 2008,69307,38.616835,-121.439146 6001 MCMAHON DR,SACRAMENTO,95824,CA,2,1,797,Residential,Wed May 21 00:00:00 EDT 2008,81900,38.51947,-121.435768 5828 PEPPERMILL CT,SACRAMENTO,95841,CA,3,1,1122,Condo,Wed May 21 00:00:00 EDT 2008,89921,38.662595,-121.327813 6048 OGDEN NASH WAY,SACRAMENTO,95842,CA,3,2,1104,Residential,Wed May 21 00:00:00 EDT 2008,90895,38.681659,-121.351705 2561 19TH AVE,SACRAMENTO,95820,CA,3,1,1177,Residential,Wed May 21 00:00:00 EDT 2008,91002,38.535092,-121.481367 11150 TRINITY RIVER DR Unit 114,RANCHO CORDOVA,95670,CA,2,2,941,Condo,Wed May 21 00:00:00 EDT 2008,94905,38.621188,-121.270555 7325 10TH ST,RIO LINDA,95673,CA,3,2,1146,Residential,Wed May 21 00:00:00 EDT 2008,98937,38.700909,-121.442979 645 MORRISON AVE,SACRAMENTO,95838,CA,3,2,909,Residential,Wed May 21 00:00:00 EDT 2008,100309,38.637663,-121.45152 4085 FAWN CIR,SACRAMENTO,95823,CA,3,2,1289,Residential,Wed May 21 00:00:00 EDT 2008,106250,38.470746,-121.458918 2930 LA ROSA RD,SACRAMENTO,95815,CA,1,1,871,Residential,Wed May 21 00:00:00 EDT 2008,106852,38.618698,-121.435833 2113 KIRK WAY,SACRAMENTO,95822,CA,3,1,1020,Residential,Wed May 21 00:00:00 EDT 2008,107502,38.482215,-121.492603 4533 LOCH HAVEN WAY,SACRAMENTO,95842,CA,2,2,1022,Residential,Wed May 21 00:00:00 EDT 2008,108750,38.672914,-121.35934 7340 HAMDEN PL,SACRAMENTO,95842,CA,2,2,1134,Condo,Wed May 21 00:00:00 EDT 2008,110700,38.700051,-121.351278 6715 6TH ST,RIO LINDA,95673,CA,2,1,844,Residential,Wed May 21 00:00:00 EDT 2008,113263,38.689591,-121.452239 6236 LONGFORD DR Unit 1,CITRUS HEIGHTS,95621,CA,2,1,795,Condo,Wed May 21 00:00:00 EDT 2008,116250,38.679776,-121.314089 250 PERALTA AVE,SACRAMENTO,95833,CA,2,1,588,Residential,Wed May 21 00:00:00 EDT 2008,120000,38.612099,-121.469095 113 LEEWILL AVE,RIO LINDA,95673,CA,3,2,1356,Residential,Wed May 21 00:00:00 EDT 2008,121630,38.689999,-121.46322 6118 STONEHAND AVE,CITRUS HEIGHTS,95621,CA,3,2,1118,Residential,Wed May 21 00:00:00 EDT 2008,122000,38.707851,-121.320707 4882 BANDALIN WAY,SACRAMENTO,95823,CA,4,2,1329,Residential,Wed May 21 00:00:00 EDT 2008,122682,38.468173,-121.444071 7511 OAKVALE CT,NORTH HIGHLANDS,95660,CA,4,2,1240,Residential,Wed May 21 00:00:00 EDT 2008,123000,38.702792,-121.38221 9 PASTURE CT,SACRAMENTO,95834,CA,3,2,1601,Residential,Wed May 21 00:00:00 EDT 2008,124100,38.628631,-121.488097 3729 BAINBRIDGE DR,NORTH HIGHLANDS,95660,CA,3,2,901,Residential,Wed May 21 00:00:00 EDT 2008,125000,38.701499,-121.37622 3828 BLACKFOOT WAY,ANTELOPE,95843,CA,3,2,1088,Residential,Wed May 21 00:00:00 EDT 2008,126640,38.70974,-121.37377 4108 NORTON WAY,SACRAMENTO,95820,CA,3,1,963,Residential,Wed May 21 00:00:00 EDT 2008,127281,38.537526,-121.478315 1469 JANRICK AVE,SACRAMENTO,95832,CA,3,2,1119,Residential,Wed May 21 00:00:00 EDT 2008,129000,38.476472,-121.501711 9861 CULP WAY,SACRAMENTO,95827,CA,4,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,131200,38.558423,-121.327948 7825 CREEK VALLEY CIR,SACRAMENTO,95828,CA,3,2,1248,Residential,Wed May 21 00:00:00 EDT 2008,132000,38.472122,-121.404199 5201 LAGUNA OAKS DR Unit 140,ELK GROVE,95758,CA,2,2,1039,Condo,Wed May 21 00:00:00 EDT 2008,133000,38.423251,-121.444489 6768 MEDORA DR,NORTH HIGHLANDS,95660,CA,3,2,1152,Residential,Wed May 21 00:00:00 EDT 2008,134555,38.691161,-121.37192 3100 EXPLORER DR,SACRAMENTO,95827,CA,3,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,136500,38.566663,-121.332644 7944 DOMINION WAY,ELVERTA,95626,CA,3,2,1116,Residential,Wed May 21 00:00:00 EDT 2008,138750,38.713182,-121.411227 5201 LAGUNA OAKS DR Unit 162,ELK GROVE,95758,CA,2,2,1039,Condo,Wed May 21 00:00:00 EDT 2008,141000,38.423251,-121.444489 3920 SHINING STAR DR,SACRAMENTO,95823,CA,3,2,1418,Residential,Wed May 21 00:00:00 EDT 2008,146250,38.48742,-121.462459 5031 CORVAIR ST,NORTH HIGHLANDS,95660,CA,3,2,1082,Residential,Wed May 21 00:00:00 EDT 2008,147308,38.658246,-121.375469 7661 NIXOS WAY,SACRAMENTO,95823,CA,4,2,1472,Residential,Wed May 21 00:00:00 EDT 2008,148750,38.479553,-121.463317 7044 CARTHY WAY,SACRAMENTO,95828,CA,4,2,1146,Residential,Wed May 21 00:00:00 EDT 2008,149593,38.49857,-121.420925 2442 LARKSPUR LN,SACRAMENTO,95825,CA,1,1,760,Condo,Wed May 21 00:00:00 EDT 2008,150000,38.58514,-121.403736 4800 WESTLAKE PKWY Unit 2109,SACRAMENTO,95835,CA,2,2,1304,Condo,Wed May 21 00:00:00 EDT 2008,152000,38.658812,-121.542345 2178 63RD AVE,SACRAMENTO,95822,CA,3,2,1207,Residential,Wed May 21 00:00:00 EDT 2008,154000,38.493955,-121.48966 8718 ELK WAY,ELK GROVE,95624,CA,3,2,1056,Residential,Wed May 21 00:00:00 EDT 2008,156896,38.41653,-121.379653 5708 RIDGEPOINT DR,ANTELOPE,95843,CA,2,2,1043,Residential,Wed May 21 00:00:00 EDT 2008,161250,38.72027,-121.331555 7315 KOALA CT,NORTH HIGHLANDS,95660,CA,4,2,1587,Residential,Wed May 21 00:00:00 EDT 2008,161500,38.699251,-121.371414 2622 ERIN DR,SACRAMENTO,95833,CA,4,1,1120,Residential,Wed May 21 00:00:00 EDT 2008,164000,38.613765,-121.488694 8421 SUNBLAZE WAY,SACRAMENTO,95823,CA,4,2,1580,Residential,Wed May 21 00:00:00 EDT 2008,165000,38.450543,-121.432538 7420 ALIX PKWY,SACRAMENTO,95823,CA,4,1,1955,Residential,Wed May 21 00:00:00 EDT 2008,166357,38.489405,-121.452811 3820 NATOMA WAY,SACRAMENTO,95838,CA,4,2,1656,Residential,Wed May 21 00:00:00 EDT 2008,166357,38.636748,-121.422159 4431 GREEN TREE DR,SACRAMENTO,95823,CA,3,2,1477,Residential,Wed May 21 00:00:00 EDT 2008,168000,38.499954,-121.454469 9417 SARA ST,ELK GROVE,95624,CA,3,2,1188,Residential,Wed May 21 00:00:00 EDT 2008,170000,38.415518,-121.370527 8299 HALBRITE WAY,SACRAMENTO,95828,CA,4,2,1590,Residential,Wed May 21 00:00:00 EDT 2008,173000,38.473814,-121.4 7223 KALLIE KAY LN,SACRAMENTO,95823,CA,3,2,1463,Residential,Wed May 21 00:00:00 EDT 2008,174250,38.477553,-121.419463 8156 STEINBECK WAY,SACRAMENTO,95828,CA,4,2,1714,Residential,Wed May 21 00:00:00 EDT 2008,174313,38.474853,-121.406326 7957 VALLEY GREEN DR,SACRAMENTO,95823,CA,3,2,1185,Residential,Wed May 21 00:00:00 EDT 2008,178480,38.465184,-121.434925 1122 WILD POPPY CT,GALT,95632,CA,3,2,1406,Residential,Wed May 21 00:00:00 EDT 2008,178760,38.287789,-121.294715 4520 BOMARK WAY,SACRAMENTO,95842,CA,4,2,1943,Multi-Family,Wed May 21 00:00:00 EDT 2008,179580,38.665724,-121.358576 9012 KIEFER BLVD,SACRAMENTO,95826,CA,3,2,1172,Residential,Wed May 21 00:00:00 EDT 2008,181000,38.547011,-121.366217 5332 SANDSTONE ST,CARMICHAEL,95608,CA,3,1,1152,Residential,Wed May 21 00:00:00 EDT 2008,181872,38.662105,-121.313945 5993 SAWYER CIR,SACRAMENTO,95823,CA,4,3,1851,Residential,Wed May 21 00:00:00 EDT 2008,182587,38.4473,-121.435218 4844 CLYDEBANK WAY,ANTELOPE,95843,CA,3,2,1215,Residential,Wed May 21 00:00:00 EDT 2008,182716,38.714609,-121.347887 306 CAMELLIA WAY,GALT,95632,CA,3,2,1130,Residential,Wed May 21 00:00:00 EDT 2008,182750,38.260443,-121.297864 9021 MADISON AVE,ORANGEVALE,95662,CA,4,2,1603,Residential,Wed May 21 00:00:00 EDT 2008,183200,38.664186,-121.217511 404 6TH ST,GALT,95632,CA,3,1,1479,Residential,Wed May 21 00:00:00 EDT 2008,188741,38.251808,-121.302493 8317 SUNNY CREEK WAY,SACRAMENTO,95823,CA,3,2,1420,Residential,Wed May 21 00:00:00 EDT 2008,189000,38.459041,-121.424644 2617 BASS CT,SACRAMENTO,95826,CA,3,2,1280,Residential,Wed May 21 00:00:00 EDT 2008,192067,38.560767,-121.377471 7005 TIANT WAY,ELK GROVE,95758,CA,3,2,1586,Residential,Wed May 21 00:00:00 EDT 2008,194000,38.422811,-121.423285 7895 CABER WAY,ANTELOPE,95843,CA,3,2,1362,Residential,Wed May 21 00:00:00 EDT 2008,194818,38.711279,-121.393449 7624 BOGEY CT,SACRAMENTO,95828,CA,4,4,2162,Multi-Family,Wed May 21 00:00:00 EDT 2008,195000,38.48009,-121.415102 6930 HAMPTON COVE WAY,SACRAMENTO,95823,CA,3,2,1266,Residential,Wed May 21 00:00:00 EDT 2008,198000,38.44004,-121.421012 8708 MESA BROOK WAY,ELK GROVE,95624,CA,4,2,1715,Residential,Wed May 21 00:00:00 EDT 2008,199500,38.44076,-121.385792 120 GRANT LN,FOLSOM,95630,CA,3,2,1820,Residential,Wed May 21 00:00:00 EDT 2008,200000,38.687742,-121.17104 5907 ELLERSLEE DR,CARMICHAEL,95608,CA,3,1,936,Residential,Wed May 21 00:00:00 EDT 2008,200000,38.664468,-121.32683 17 SERASPI CT,SACRAMENTO,95834,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,206000,38.631481,-121.50188 170 PENHOW CIR,SACRAMENTO,95834,CA,3,2,1511,Residential,Wed May 21 00:00:00 EDT 2008,208000,38.653439,-121.535169 8345 STAR THISTLE WAY,SACRAMENTO,95823,CA,4,2,1590,Residential,Wed May 21 00:00:00 EDT 2008,212864,38.454349,-121.439239 9080 FRESCA WAY,ELK GROVE,95758,CA,4,2,1596,Residential,Wed May 21 00:00:00 EDT 2008,221000,38.427818,-121.424026 391 NATALINO CIR,SACRAMENTO,95835,CA,2,2,1341,Residential,Wed May 21 00:00:00 EDT 2008,221000,38.67307,-121.506373 8373 BLACKMAN WAY,ELK GROVE,95624,CA,5,3,2136,Residential,Wed May 21 00:00:00 EDT 2008,223058,38.435436,-121.394536 9837 CORTE DORADO CT,ELK GROVE,95624,CA,4,2,1616,Residential,Wed May 21 00:00:00 EDT 2008,227887,38.400676,-121.38101 5037 J PKWY,SACRAMENTO,95823,CA,3,2,1478,Residential,Wed May 21 00:00:00 EDT 2008,231477,38.491399,-121.443547 10245 LOS PALOS DR,RANCHO CORDOVA,95670,CA,3,2,1287,Residential,Wed May 21 00:00:00 EDT 2008,234697,38.593699,-121.31089 6613 NAVION DR,CITRUS HEIGHTS,95621,CA,4,2,1277,Residential,Wed May 21 00:00:00 EDT 2008,235000,38.702855,-121.31308 2887 AZEVEDO DR,SACRAMENTO,95833,CA,4,2,1448,Residential,Wed May 21 00:00:00 EDT 2008,236000,38.618457,-121.509439 9186 KINBRACE CT,SACRAMENTO,95829,CA,4,3,2235,Residential,Wed May 21 00:00:00 EDT 2008,236685,38.463355,-121.358936 4243 MIDDLEBURY WAY,MATHER,95655,CA,3,2,2093,Residential,Wed May 21 00:00:00 EDT 2008,237800,38.547991,-121.280483 1028 FALLON PLACE CT,RIO LINDA,95673,CA,3,2,1193,Residential,Wed May 21 00:00:00 EDT 2008,240122,38.693818,-121.441153 4804 NORIKER DR,ELK GROVE,95757,CA,3,2,2163,Residential,Wed May 21 00:00:00 EDT 2008,242638,38.400974,-121.448424 7713 HARVEST WOODS DR,SACRAMENTO,95828,CA,3,2,1269,Residential,Wed May 21 00:00:00 EDT 2008,244000,38.478198,-121.412911 2866 KARITSA AVE,SACRAMENTO,95833,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,244500,38.626671,-121.52597 6913 RICHEVE WAY,SACRAMENTO,95828,CA,3,1,958,Residential,Wed May 21 00:00:00 EDT 2008,244960,38.502519,-121.420769 8636 TEGEA WAY,ELK GROVE,95624,CA,5,3,2508,Residential,Wed May 21 00:00:00 EDT 2008,245918,38.443832,-121.382087 5448 MAIDSTONE WAY,CITRUS HEIGHTS,95621,CA,3,2,1305,Residential,Wed May 21 00:00:00 EDT 2008,250000,38.665395,-121.293288 18 OLLIE CT,ELK GROVE,95758,CA,4,2,1591,Residential,Wed May 21 00:00:00 EDT 2008,250000,38.444909,-121.412345 4010 ALEX LN,CARMICHAEL,95608,CA,2,2,1326,Condo,Wed May 21 00:00:00 EDT 2008,250134,38.637028,-121.312963 4901 MILLNER WAY,ELK GROVE,95757,CA,3,2,1843,Residential,Wed May 21 00:00:00 EDT 2008,254200,38.38692,-121.447349 4818 BRITTNEY LEE CT,SACRAMENTO,95841,CA,4,2,1921,Residential,Wed May 21 00:00:00 EDT 2008,254200,38.653917,-121.34218 5529 LAGUNA PARK DR,ELK GROVE,95758,CA,5,3,2790,Residential,Wed May 21 00:00:00 EDT 2008,258000,38.42568,-121.438062 230 CANDELA CIR,SACRAMENTO,95835,CA,3,2,1541,Residential,Wed May 21 00:00:00 EDT 2008,260000,38.656251,-121.547572 4900 71ST ST,SACRAMENTO,95820,CA,3,1,1018,Residential,Wed May 21 00:00:00 EDT 2008,260014,38.53151,-121.421089 12209 CONSERVANCY WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,263500,38.553867,-121.219141 4236 NATOMAS CENTRAL DR,SACRAMENTO,95834,CA,3,2,1672,Condo,Wed May 21 00:00:00 EDT 2008,265000,38.648879,-121.544023 5615 LUPIN LN,POLLOCK PINES,95726,CA,3,2,1380,Residential,Wed May 21 00:00:00 EDT 2008,265000,38.708315,-120.603872 5625 JAMES WAY,SACRAMENTO,95822,CA,3,1,975,Residential,Wed May 21 00:00:00 EDT 2008,271742,38.523947,-121.484946 7842 LAHONTAN CT,SACRAMENTO,95829,CA,4,3,2372,Residential,Wed May 21 00:00:00 EDT 2008,273750,38.472976,-121.318633 6850 21ST ST,SACRAMENTO,95822,CA,3,2,1446,Residential,Wed May 21 00:00:00 EDT 2008,275086,38.502194,-121.490795 2900 BLAIR RD,POLLOCK PINES,95726,CA,2,2,1284,Residential,Wed May 21 00:00:00 EDT 2008,280908,38.75485,-120.60476 2064 EXPEDITION WAY,SACRAMENTO,95832,CA,4,3,3009,Residential,Wed May 21 00:00:00 EDT 2008,280987,38.474099,-121.490711 2912 NORCADE CIR,SACRAMENTO,95826,CA,8,4,3612,Multi-Family,Wed May 21 00:00:00 EDT 2008,282400,38.559505,-121.364839 9507 SEA CLIFF WAY,ELK GROVE,95758,CA,4,2,2056,Residential,Wed May 21 00:00:00 EDT 2008,285000,38.410992,-121.479043 8882 AUTUMN GOLD CT,ELK GROVE,95624,CA,4,2,1993,Residential,Wed May 21 00:00:00 EDT 2008,287417,38.4439,-121.37255 5322 WHITE LOTUS WAY,ELK GROVE,95757,CA,3,2,1857,Residential,Wed May 21 00:00:00 EDT 2008,291000,38.391538,-121.442596 1838 CASTRO WAY,SACRAMENTO,95818,CA,2,1,1126,Residential,Wed May 21 00:00:00 EDT 2008,292024,38.556098,-121.490787 10158 CRAWFORD WAY,SACRAMENTO,95827,CA,4,4,2213,Multi-Family,Wed May 21 00:00:00 EDT 2008,297000,38.5703,-121.315735 7731 MASTERS ST,ELK GROVE,95758,CA,5,3,2494,Residential,Wed May 21 00:00:00 EDT 2008,297000,38.442031,-121.410873 4925 PERCHERON DR,ELK GROVE,95757,CA,3,2,1843,Residential,Wed May 21 00:00:00 EDT 2008,298000,38.40154,-121.447649 2010 PROMONTORY POINT LN,GOLD RIVER,95670,CA,2,2,1520,Residential,Wed May 21 00:00:00 EDT 2008,299000,38.62869,-121.261669 4727 SAVOIE WAY,SACRAMENTO,95835,CA,5,3,2800,Residential,Wed May 21 00:00:00 EDT 2008,304037,38.658182,-121.549521 8664 MAGNOLIA HILL WAY,ELK GROVE,95624,CA,4,2,2309,Residential,Wed May 21 00:00:00 EDT 2008,311000,38.442352,-121.389675 9570 HARVEST ROSE WAY,SACRAMENTO,95827,CA,5,3,2367,Residential,Wed May 21 00:00:00 EDT 2008,315537,38.555993,-121.340352 4359 CREGAN CT,RANCHO CORDOVA,95742,CA,5,4,3516,Residential,Wed May 21 00:00:00 EDT 2008,320000,38.545128,-121.224922 5337 DUSTY ROSE WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,320000,38.528575,-121.2286 8929 SUTTERS GOLD DR,SACRAMENTO,95826,CA,4,3,1914,Residential,Wed May 21 00:00:00 EDT 2008,328360,38.550848,-121.370224 8025 PEERLESS AVE,ORANGEVALE,95662,CA,2,1,1690,Residential,Wed May 21 00:00:00 EDT 2008,334150,38.71147,-121.216214 4620 WELERA WAY,ELK GROVE,95757,CA,3,3,2725,Residential,Wed May 21 00:00:00 EDT 2008,335750,38.398609,-121.450148 9723 TERRAPIN CT,ELK GROVE,95757,CA,4,3,2354,Residential,Wed May 21 00:00:00 EDT 2008,335750,38.403492,-121.430224 2115 SMOKESTACK WAY,SACRAMENTO,95833,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,339500,38.602416,-121.542965 100 REBECCA WAY,FOLSOM,95630,CA,3,2,2185,Residential,Wed May 21 00:00:00 EDT 2008,344250,38.68479,-121.149199 9488 OAK VILLAGE WAY,ELK GROVE,95758,CA,4,2,1801,Residential,Wed May 21 00:00:00 EDT 2008,346210,38.41333,-121.404999 8495 DARTFORD DR,SACRAMENTO,95823,CA,3,3,1961,Residential,Wed May 21 00:00:00 EDT 2008,347029,38.448507,-121.421346 6708 PONTA DO SOL WAY,ELK GROVE,95757,CA,4,2,3134,Residential,Wed May 21 00:00:00 EDT 2008,347650,38.380635,-121.425538 4143 SEA MEADOW WAY,SACRAMENTO,95823,CA,4,3,1915,Residential,Wed May 21 00:00:00 EDT 2008,351300,38.46534,-121.457519 3020 RICHARDSON CIR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Wed May 21 00:00:00 EDT 2008,352000,38.691299,-121.081752 8082 LINDA ISLE LN,SACRAMENTO,95831,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,370000,38.4772,-121.5215 15300 MURIETA SOUTH PKWY,RANCHO MURIETA,95683,CA,4,3,2734,Residential,Wed May 21 00:00:00 EDT 2008,370500,38.4874,-121.075129 11215 SHARRMONT CT,WILTON,95693,CA,3,2,2110,Residential,Wed May 21 00:00:00 EDT 2008,372000,38.35062,-121.228349 7105 DANBERG WAY,ELK GROVE,95757,CA,5,3,3164,Residential,Wed May 21 00:00:00 EDT 2008,375000,38.4019,-121.420388 5579 JERRY LITELL WAY,SACRAMENTO,95835,CA,5,3,3599,Residential,Wed May 21 00:00:00 EDT 2008,381300,38.677126,-121.500519 1050 FOXHALL WAY,SACRAMENTO,95831,CA,4,2,2054,Residential,Wed May 21 00:00:00 EDT 2008,381942,38.509819,-121.519661 7837 ABBINGTON WAY,ANTELOPE,95843,CA,4,2,1830,Residential,Wed May 21 00:00:00 EDT 2008,387731,38.709873,-121.339472 1300 F ST,SACRAMENTO,95814,CA,3,3,1627,Residential,Wed May 21 00:00:00 EDT 2008,391000,38.58355,-121.487289 6801 RAWLEY WAY,ELK GROVE,95757,CA,4,3,3440,Residential,Wed May 21 00:00:00 EDT 2008,394470,38.408351,-121.423925 1693 SHELTER COVE DR,GREENWOOD,95635,CA,3,2,2846,Residential,Wed May 21 00:00:00 EDT 2008,395000,38.945357,-120.908822 9361 WADDELL LN,ELK GROVE,95624,CA,4,3,2359,Residential,Wed May 21 00:00:00 EDT 2008,400186,38.450829,-121.349928 10 SEA FOAM CT,SACRAMENTO,95831,CA,3,3,2052,Residential,Wed May 21 00:00:00 EDT 2008,415000,38.487885,-121.545947 6945 RIO TEJO WAY,ELK GROVE,95757,CA,5,3,3433,Residential,Wed May 21 00:00:00 EDT 2008,425000,38.385638,-121.422616 4186 TULIP PARK WAY,RANCHO CORDOVA,95742,CA,5,3,3615,Residential,Wed May 21 00:00:00 EDT 2008,430000,38.550617,-121.23526 9278 DAIRY CT,ELK GROVE,95624,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,445000,38.420338,-121.363757 207 ORANGE BLOSSOM CIR Unit C,FOLSOM,95630,CA,5,3,2687,Residential,Wed May 21 00:00:00 EDT 2008,460000,38.646273,-121.175322 6507 RIO DE ONAR WAY,ELK GROVE,95757,CA,4,3,2724,Residential,Wed May 21 00:00:00 EDT 2008,461000,38.38253,-121.428007 7004 RAWLEY WAY,ELK GROVE,95757,CA,4,3,3440,Residential,Wed May 21 00:00:00 EDT 2008,489332,38.406421,-121.422081 6503 RIO DE ONAR WAY,ELK GROVE,95757,CA,5,4,3508,Residential,Wed May 21 00:00:00 EDT 2008,510000,38.38253,-121.428038 2217 APPALOOSA CT,FOLSOM,95630,CA,4,2,2462,Residential,Wed May 21 00:00:00 EDT 2008,539000,38.655167,-121.090178 868 HILDEBRAND CIR,FOLSOM,95630,CA,0,0,0,Residential,Wed May 21 00:00:00 EDT 2008,585000,38.670947,-121.097727 6030 PALERMO WAY,EL DORADO HILLS,95762,CA,4,3,0,Residential,Wed May 21 00:00:00 EDT 2008,600000,38.672761,-121.050378 4070 REDONDO DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Wed May 21 00:00:00 EDT 2008,606238,38.666807,-121.06483 4004 CRESTA WAY,SACRAMENTO,95864,CA,3,3,2325,Residential,Wed May 21 00:00:00 EDT 2008,660000,38.591618,-121.370626 315 JUMEL CT,EL DORADO HILLS,95762,CA,6,5,0,Residential,Wed May 21 00:00:00 EDT 2008,830000,38.669931,-121.05958 6272 LONGFORD DR Unit 1,CITRUS HEIGHTS,95621,CA,2,1,795,Condo,Tue May 20 00:00:00 EDT 2008,69000,38.680923,-121.313945 3432 Y ST,SACRAMENTO,95817,CA,4,2,1099,Residential,Tue May 20 00:00:00 EDT 2008,70000,38.554967,-121.468046 9512 EMERALD PARK DR Unit 3,ELK GROVE,95624,CA,2,1,840,Condo,Tue May 20 00:00:00 EDT 2008,71000,38.40573,-121.369832 3132 CLAY ST,SACRAMENTO,95815,CA,2,1,800,Residential,Tue May 20 00:00:00 EDT 2008,78000,38.624678,-121.439203 5221 38TH AVE,SACRAMENTO,95824,CA,2,1,746,Residential,Tue May 20 00:00:00 EDT 2008,78400,38.518044,-121.443555 6112 HERMOSA ST,SACRAMENTO,95822,CA,3,1,1067,Residential,Tue May 20 00:00:00 EDT 2008,80000,38.515125,-121.480416 483 ARCADE BLVD,SACRAMENTO,95815,CA,4,2,1316,Residential,Tue May 20 00:00:00 EDT 2008,89000,38.623571,-121.454884 671 SONOMA AVE,SACRAMENTO,95815,CA,3,1,1337,Residential,Tue May 20 00:00:00 EDT 2008,90000,38.622953,-121.450142 5980 79TH ST,SACRAMENTO,95824,CA,2,1,868,Residential,Tue May 20 00:00:00 EDT 2008,90000,38.518373,-121.411779 7607 ELDER CREEK RD,SACRAMENTO,95824,CA,3,1,924,Residential,Tue May 20 00:00:00 EDT 2008,92000,38.51055,-121.414768 5028 14TH AVE,SACRAMENTO,95820,CA,2,1,610,Residential,Tue May 20 00:00:00 EDT 2008,93675,38.53942,-121.446894 14788 NATCHEZ CT,RANCHO MURIETA,95683,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,97750,38.492287,-121.100032 1069 ACACIA AVE,SACRAMENTO,95815,CA,2,1,1220,Residential,Tue May 20 00:00:00 EDT 2008,98000,38.621998,-121.442238 5201 LAGUNA OAKS DR Unit 199,ELK GROVE,95758,CA,1,1,722,Condo,Tue May 20 00:00:00 EDT 2008,98000,38.423251,-121.444489 3847 LAS PASAS WAY,SACRAMENTO,95864,CA,3,1,1643,Residential,Tue May 20 00:00:00 EDT 2008,99000,38.588672,-121.373916 5201 LAGUNA OAKS DR Unit 172,ELK GROVE,95758,CA,1,1,722,Condo,Tue May 20 00:00:00 EDT 2008,100000,38.423251,-121.444489 1121 CREEKSIDE WAY,GALT,95632,CA,3,1,1080,Residential,Tue May 20 00:00:00 EDT 2008,106716,38.241514,-121.312199 5307 CABRILLO WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Tue May 20 00:00:00 EDT 2008,111000,38.52712,-121.435348 3725 DON JULIO BLVD,NORTH HIGHLANDS,95660,CA,3,1,1051,Residential,Tue May 20 00:00:00 EDT 2008,111000,38.67895,-121.379406 4803 MCCLOUD DR,SACRAMENTO,95842,CA,2,2,967,Residential,Tue May 20 00:00:00 EDT 2008,114800,38.682279,-121.352817 10542 SILVERWOOD WAY,RANCHO CORDOVA,95670,CA,3,1,1098,Residential,Tue May 20 00:00:00 EDT 2008,120108,38.587156,-121.295778 6318 39TH AVE,SACRAMENTO,95824,CA,3,1,1050,Residential,Tue May 20 00:00:00 EDT 2008,123225,38.518942,-121.430158 211 MCDANIEL CIR,SACRAMENTO,95838,CA,3,2,1110,Residential,Tue May 20 00:00:00 EDT 2008,123750,38.636565,-121.460383 3800 LYNHURST WAY,NORTH HIGHLANDS,95660,CA,3,1,888,Residential,Tue May 20 00:00:00 EDT 2008,125000,38.650445,-121.374861 6139 HERMOSA ST,SACRAMENTO,95822,CA,3,2,1120,Residential,Tue May 20 00:00:00 EDT 2008,125000,38.514665,-121.480411 2505 RHINE WAY,ELVERTA,95626,CA,3,2,1080,Residential,Tue May 20 00:00:00 EDT 2008,126000,38.717976,-121.407684 3692 PAYNE WAY,NORTH HIGHLANDS,95660,CA,3,1,957,Residential,Tue May 20 00:00:00 EDT 2008,129000,38.66654,-121.378298 604 MORRISON AVE,SACRAMENTO,95838,CA,2,1,952,Residential,Tue May 20 00:00:00 EDT 2008,134000,38.637678,-121.452476 648 SANTA ANA AVE,SACRAMENTO,95838,CA,3,2,1211,Residential,Tue May 20 00:00:00 EDT 2008,135000,38.658478,-121.450409 14 ASHLEY OAKS CT,SACRAMENTO,95815,CA,3,2,1264,Residential,Tue May 20 00:00:00 EDT 2008,135500,38.61779,-121.436765 3174 NORTHVIEW DR,SACRAMENTO,95833,CA,3,1,1080,Residential,Tue May 20 00:00:00 EDT 2008,140000,38.623817,-121.477827 840 TRANQUIL LN,GALT,95632,CA,3,2,1266,Residential,Tue May 20 00:00:00 EDT 2008,140000,38.270617,-121.299205 5333 PRIMROSE DR Unit 19A,FAIR OAKS,95628,CA,2,2,994,Condo,Tue May 20 00:00:00 EDT 2008,142500,38.662785,-121.276272 1035 MILLET WAY,SACRAMENTO,95834,CA,3,2,1202,Residential,Tue May 20 00:00:00 EDT 2008,143500,38.631056,-121.48508 5201 LAGUNA OAKS DR Unit 126,ELK GROVE,95758,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,145000,38.423251,-121.444489 3328 22ND AVE,SACRAMENTO,95820,CA,2,1,722,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.532727,-121.470783 8001 HARTWICK WAY,SACRAMENTO,95828,CA,4,2,1448,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.488623,-121.410582 7812 HARTWICK WAY,SACRAMENTO,95828,CA,3,2,1188,Residential,Tue May 20 00:00:00 EDT 2008,145000,38.488611,-121.412808 4207 PAINTER WAY,NORTH HIGHLANDS,95660,CA,4,2,1183,Residential,Tue May 20 00:00:00 EDT 2008,146000,38.692915,-121.367497 7458 WINKLEY WAY,SACRAMENTO,95822,CA,3,1,1320,Residential,Tue May 20 00:00:00 EDT 2008,148500,38.487444,-121.491366 8354 SUNRISE WOODS WAY,SACRAMENTO,95828,CA,3,2,1117,Residential,Tue May 20 00:00:00 EDT 2008,149000,38.473288,-121.3963 8116 COTTONMILL CIR,SACRAMENTO,95828,CA,3,2,1364,Residential,Tue May 20 00:00:00 EDT 2008,150000,38.482876,-121.405912 4660 CEDARWOOD WAY,SACRAMENTO,95823,CA,4,2,1310,Residential,Tue May 20 00:00:00 EDT 2008,150000,38.484834,-121.449316 9254 HARROGATE WAY,ELK GROVE,95758,CA,2,2,1006,Residential,Tue May 20 00:00:00 EDT 2008,152000,38.420138,-121.412179 6716 TAREYTON WAY,CITRUS HEIGHTS,95621,CA,3,2,1104,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.693724,-121.307169 2028 ROBERT WAY,SACRAMENTO,95825,CA,2,1,810,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.609982,-121.419263 9346 AIZENBERG CIR,ELK GROVE,95624,CA,2,2,1123,Residential,Tue May 20 00:00:00 EDT 2008,156000,38.41875,-121.370019 4524 LOCH HAVEN WAY,SACRAMENTO,95842,CA,2,1,904,Residential,Tue May 20 00:00:00 EDT 2008,157788,38.67273,-121.359645 7140 BLUE SPRINGS WAY,CITRUS HEIGHTS,95621,CA,3,2,1156,Residential,Tue May 20 00:00:00 EDT 2008,161653,38.720653,-121.302241 4631 11TH AVE,SACRAMENTO,95820,CA,2,1,1321,Residential,Tue May 20 00:00:00 EDT 2008,161829,38.541965,-121.452132 3228 BAGGAN CT,ANTELOPE,95843,CA,3,2,1392,Residential,Tue May 20 00:00:00 EDT 2008,165000,38.715346,-121.388163 8515 DARTFORD DR,SACRAMENTO,95823,CA,3,2,1439,Residential,Tue May 20 00:00:00 EDT 2008,168000,38.448288,-121.420719 4500 TIPPWOOD WAY,SACRAMENTO,95842,CA,3,2,1159,Residential,Tue May 20 00:00:00 EDT 2008,169000,38.69951,-121.359989 2460 EL ROCCO WAY,RANCHO CORDOVA,95670,CA,3,2,1671,Residential,Tue May 20 00:00:00 EDT 2008,175000,38.591477,-121.31534 8244 SUNBIRD WAY,SACRAMENTO,95823,CA,3,2,1740,Residential,Tue May 20 00:00:00 EDT 2008,176250,38.457654,-121.431381 5841 VALLEY VALE WAY,SACRAMENTO,95823,CA,3,2,1265,Residential,Tue May 20 00:00:00 EDT 2008,179000,38.461283,-121.434322 7863 CRESTLEIGH CT,ANTELOPE,95843,CA,2,2,1007,Residential,Tue May 20 00:00:00 EDT 2008,180000,38.710889,-121.358876 7129 SPRINGMONT DR,ELK GROVE,95758,CA,3,2,1716,Residential,Tue May 20 00:00:00 EDT 2008,180400,38.417649,-121.420294 8284 RED FOX WAY,ELK GROVE,95758,CA,4,2,1685,Residential,Tue May 20 00:00:00 EDT 2008,182000,38.417182,-121.397231 2219 EL CANTO CIR,RANCHO CORDOVA,95670,CA,4,2,1829,Residential,Tue May 20 00:00:00 EDT 2008,184500,38.592383,-121.318669 8907 GEMWOOD WAY,ELK GROVE,95758,CA,3,2,1555,Residential,Tue May 20 00:00:00 EDT 2008,185000,38.435471,-121.441173 5925 MALEVILLE AVE,CARMICHAEL,95608,CA,4,2,1120,Residential,Tue May 20 00:00:00 EDT 2008,189000,38.666564,-121.325717 7031 CANEVALLEY CIR,CITRUS HEIGHTS,95621,CA,3,2,1137,Residential,Tue May 20 00:00:00 EDT 2008,194000,38.718693,-121.303619 3949 WILDROSE WAY,SACRAMENTO,95826,CA,3,1,1174,Residential,Tue May 20 00:00:00 EDT 2008,195000,38.543697,-121.366683 4437 MITCHUM CT,ANTELOPE,95843,CA,3,2,1393,Residential,Tue May 20 00:00:00 EDT 2008,200000,38.704407,-121.36113 2778 KAWEAH CT,CAMERON PARK,95682,CA,3,1,0,Residential,Tue May 20 00:00:00 EDT 2008,201000,38.694052,-120.995589 1636 ALLENWOOD CIR,LINCOLN,95648,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,202500,38.879192,-121.309477 8151 QUAIL RIDGE CT,SACRAMENTO,95828,CA,3,2,1289,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.461296,-121.390858 4899 WIND CREEK DR,SACRAMENTO,95838,CA,4,2,1799,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.655887,-121.446119 2370 BIG CANYON CREEK RD,PLACERVILLE,95667,CA,3,2,0,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.74458,-120.794254 6049 HAMBURG WAY,SACRAMENTO,95823,CA,4,3,1953,Residential,Tue May 20 00:00:00 EDT 2008,205000,38.443253,-121.431992 4232 71ST ST,SACRAMENTO,95820,CA,2,1,723,Residential,Tue May 20 00:00:00 EDT 2008,207000,38.536741,-121.42115 3361 BOW MAR CT,CAMERON PARK,95682,CA,2,2,0,Residential,Tue May 20 00:00:00 EDT 2008,210000,38.69437,-120.996602 1889 COLD SPRINGS RD,PLACERVILLE,95667,CA,2,1,948,Residential,Tue May 20 00:00:00 EDT 2008,211500,38.739774,-120.860243 5805 HIMALAYA WAY,CITRUS HEIGHTS,95621,CA,4,2,1578,Residential,Tue May 20 00:00:00 EDT 2008,215000,38.696489,-121.328555 7944 SYLVAN OAK WAY,CITRUS HEIGHTS,95610,CA,3,2,1317,Residential,Tue May 20 00:00:00 EDT 2008,215000,38.710388,-121.261096 3139 SPOONWOOD WAY Unit 1,SACRAMENTO,95833,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,215500,38.626582,-121.52151 6217 LEOLA WAY,SACRAMENTO,95824,CA,3,1,1360,Residential,Tue May 20 00:00:00 EDT 2008,222381,38.513066,-121.451909 2340 HURLEY WAY,SACRAMENTO,95825,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,225000,38.588816,-121.408549 3035 BRUNNET LN,SACRAMENTO,95833,CA,3,2,1522,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.624762,-121.522775 3025 EL PRADO WAY,SACRAMENTO,95825,CA,4,2,1751,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.606603,-121.394147 9387 GRANITE FALLS CT,ELK GROVE,95624,CA,3,2,1465,Residential,Tue May 20 00:00:00 EDT 2008,225000,38.419214,-121.348533 9257 CALDERA WAY,SACRAMENTO,95826,CA,4,2,1605,Residential,Tue May 20 00:00:00 EDT 2008,228000,38.55821,-121.355022 441 ARLINGDALE CIR,RIO LINDA,95673,CA,4,2,1475,Residential,Tue May 20 00:00:00 EDT 2008,229665,38.702893,-121.454949 2284 LOS ROBLES RD,MEADOW VISTA,95722,CA,3,1,1216,Residential,Tue May 20 00:00:00 EDT 2008,230000,39.008159,-121.03623 8164 CHENIN BLANC LN,FAIR OAKS,95628,CA,2,2,1315,Residential,Tue May 20 00:00:00 EDT 2008,230000,38.665644,-121.259969 4620 CHAMBERLIN CIR,ELK GROVE,95757,CA,3,2,1567,Residential,Tue May 20 00:00:00 EDT 2008,230000,38.390557,-121.449805 5340 BIRK WAY,SACRAMENTO,95835,CA,3,2,1776,Residential,Tue May 20 00:00:00 EDT 2008,234000,38.672495,-121.515251 51 ANJOU CIR,SACRAMENTO,95835,CA,3,2,2187,Residential,Tue May 20 00:00:00 EDT 2008,235000,38.661658,-121.540633 2125 22ND AVE,SACRAMENTO,95822,CA,3,1,1291,Residential,Tue May 20 00:00:00 EDT 2008,236250,38.534596,-121.493121 611 BLOSSOM ROCK LN,FOLSOM,95630,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,240000,38.6457,-121.1197 8830 ADUR RD,ELK GROVE,95624,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,242000,38.43742,-121.372876 7344 BUTTERBALL WAY,SACRAMENTO,95842,CA,3,2,1503,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.699489,-121.361828 8219 GWINHURST CIR,SACRAMENTO,95828,CA,4,3,2491,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.459711,-121.384283 3240 S ST,SACRAMENTO,95816,CA,2,1,1269,Residential,Tue May 20 00:00:00 EDT 2008,245000,38.562296,-121.467489 221 PICASSO CIR,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.676658,-121.528128 5706 GREENACRES WAY,ORANGEVALE,95662,CA,3,2,1176,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.669882,-121.213533 6900 LONICERA DR,ORANGEVALE,95662,CA,4,2,1456,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.692199,-121.250975 419 DAWNRIDGE RD,ROSEVILLE,95678,CA,3,2,1498,Residential,Tue May 20 00:00:00 EDT 2008,250000,38.725283,-121.297953 5312 MARBURY WAY,ANTELOPE,95843,CA,3,2,1574,Residential,Tue May 20 00:00:00 EDT 2008,255000,38.710221,-121.341651 6344 BONHAM CIR,CITRUS HEIGHTS,95610,CA,5,4,2085,Multi-Family,Tue May 20 00:00:00 EDT 2008,256054,38.682358,-121.272876 8207 YORKTON WAY,SACRAMENTO,95829,CA,3,2,2170,Residential,Tue May 20 00:00:00 EDT 2008,257729,38.45967,-121.360461 7922 MANSELL WAY,ELK GROVE,95758,CA,4,2,1595,Residential,Tue May 20 00:00:00 EDT 2008,260000,38.409634,-121.410787 5712 MELBURY CIR,ANTELOPE,95843,CA,3,2,1567,Residential,Tue May 20 00:00:00 EDT 2008,261000,38.705849,-121.334701 632 NEWBRIDGE LN,LINCOLN,95648,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,261800,38.879084,-121.298586 1570 GLIDDEN AVE,SACRAMENTO,95822,CA,4,2,1253,Residential,Tue May 20 00:00:00 EDT 2008,264469,38.482704,-121.500433 8108 FILIFERA WAY,ANTELOPE,95843,CA,4,3,1768,Residential,Tue May 20 00:00:00 EDT 2008,265000,38.717042,-121.35468 230 BANKSIDE WAY,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.676937,-121.529244 5342 CALABRIA WAY,SACRAMENTO,95835,CA,4,3,2030,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.671807,-121.498274 47 NAPONEE CT,SACRAMENTO,95835,CA,3,2,1531,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.665704,-121.529096 4236 ADRIATIC SEA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,270000,38.647961,-121.543162 8864 REMBRANT CT,ELK GROVE,95624,CA,4,3,1653,Residential,Tue May 20 00:00:00 EDT 2008,275000,38.435288,-121.375703 9455 SEA CLIFF WAY,ELK GROVE,95758,CA,4,2,2056,Residential,Tue May 20 00:00:00 EDT 2008,275000,38.411522,-121.481406 9720 LITTLE HARBOR WAY,ELK GROVE,95624,CA,4,3,2494,Residential,Tue May 20 00:00:00 EDT 2008,280000,38.404934,-121.352405 8806 PHOENIX AVE,FAIR OAKS,95628,CA,3,2,1450,Residential,Tue May 20 00:00:00 EDT 2008,286013,38.660322,-121.230101 3578 LOGGERHEAD WAY,SACRAMENTO,95834,CA,4,2,2169,Residential,Tue May 20 00:00:00 EDT 2008,292000,38.633028,-121.526755 1416 LOCKHART WAY,ROSEVILLE,95747,CA,3,2,1440,Residential,Tue May 20 00:00:00 EDT 2008,292000,38.752399,-121.330328 5413 BUENA VENTURA WAY,FAIR OAKS,95628,CA,3,2,1527,Residential,Tue May 20 00:00:00 EDT 2008,293993,38.664552,-121.255937 37 WHITE BIRCH CT,ROSEVILLE,95678,CA,3,2,1401,Residential,Tue May 20 00:00:00 EDT 2008,294000,38.776327,-121.284514 405 MARLIN SPIKE WAY,SACRAMENTO,95838,CA,3,2,1411,Residential,Tue May 20 00:00:00 EDT 2008,296769,38.65783,-121.456842 1102 CHESLEY LN,LINCOLN,95648,CA,4,4,0,Residential,Tue May 20 00:00:00 EDT 2008,297500,38.864864,-121.313988 11281 STANFORD COURT LN Unit 604,GOLD RIVER,95670,CA,0,0,0,Condo,Tue May 20 00:00:00 EDT 2008,300000,38.625289,-121.260286 7320 6TH ST,RIO LINDA,95673,CA,3,1,1284,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.700553,-121.452223 993 MANTON CT,GALT,95632,CA,4,3,2307,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.272942,-121.289148 4487 PANORAMA DR,PLACERVILLE,95667,CA,3,2,1329,Residential,Tue May 20 00:00:00 EDT 2008,300000,38.694559,-120.848157 5651 OVERLEAF WAY,SACRAMENTO,95835,CA,4,2,1910,Residential,Tue May 20 00:00:00 EDT 2008,300500,38.677454,-121.494791 2015 PROMONTORY POINT LN,GOLD RIVER,95670,CA,3,2,1981,Residential,Tue May 20 00:00:00 EDT 2008,305000,38.628732,-121.261149 3224 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,306500,38.772771,-121.364877 15 VANESSA PL,SACRAMENTO,95835,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,312500,38.668692,-121.54549 1312 RENISON LN,LINCOLN,95648,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,315000,38.866409,-121.308485 8 RIVER RAFT CT,SACRAMENTO,95823,CA,4,2,2205,Residential,Tue May 20 00:00:00 EDT 2008,319789,38.447353,-121.434969 2251 LAMPLIGHT LN,LINCOLN,95648,CA,2,2,1449,Residential,Tue May 20 00:00:00 EDT 2008,330000,38.849924,-121.275729 106 FARHAM DR,FOLSOM,95630,CA,3,2,1258,Residential,Tue May 20 00:00:00 EDT 2008,330000,38.667834,-121.168578 5405 NECTAR CIR,ELK GROVE,95757,CA,3,2,2575,Residential,Tue May 20 00:00:00 EDT 2008,331000,38.387014,-121.440967 5411 10TH AVE,SACRAMENTO,95820,CA,2,1,539,Residential,Tue May 20 00:00:00 EDT 2008,334000,38.542727,-121.442449 3512 RAINSONG CIR,RANCHO CORDOVA,95670,CA,4,3,2208,Residential,Tue May 20 00:00:00 EDT 2008,336000,38.573488,-121.282809 1106 55TH ST,SACRAMENTO,95819,CA,3,1,1108,Residential,Tue May 20 00:00:00 EDT 2008,339000,38.563805,-121.436395 411 ILLSLEY WAY,FOLSOM,95630,CA,4,2,1595,Residential,Tue May 20 00:00:00 EDT 2008,339000,38.652002,-121.129504 796 BUTTERCUP CIR,GALT,95632,CA,4,2,2159,Residential,Tue May 20 00:00:00 EDT 2008,345000,38.279581,-121.300828 1230 SANDRA CIR,PLACERVILLE,95667,CA,4,3,2295,Residential,Tue May 20 00:00:00 EDT 2008,350000,38.738141,-120.784145 318 ANACAPA DR,ROSEVILLE,95678,CA,3,2,1838,Residential,Tue May 20 00:00:00 EDT 2008,356000,38.782094,-121.297133 3975 SHINING STAR DR,SACRAMENTO,95823,CA,4,2,1900,Residential,Tue May 20 00:00:00 EDT 2008,361745,38.487409,-121.461413 1620 BASLER ST,SACRAMENTO,95811,CA,4,2,1718,Residential,Tue May 20 00:00:00 EDT 2008,361948,38.591822,-121.478644 9688 NATURE TRAIL WAY,ELK GROVE,95757,CA,5,3,3389,Residential,Tue May 20 00:00:00 EDT 2008,370000,38.405224,-121.479275 5924 TANUS CIR,ROCKLIN,95677,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,380000,38.778691,-121.204292 9629 CEDAR OAK WAY,ELK GROVE,95757,CA,5,4,3260,Residential,Tue May 20 00:00:00 EDT 2008,385000,38.405527,-121.431746 3429 FERNBROOK CT,CAMERON PARK,95682,CA,3,2,2016,Residential,Tue May 20 00:00:00 EDT 2008,399000,38.664225,-121.007173 2121 HANNAH WAY,ROCKLIN,95765,CA,4,2,2607,Residential,Tue May 20 00:00:00 EDT 2008,402000,38.805749,-121.280931 10104 ANNIE ST,ELK GROVE,95757,CA,4,3,2724,Residential,Tue May 20 00:00:00 EDT 2008,406026,38.390465,-121.443479 1092 MAUGHAM CT,GALT,95632,CA,5,4,3746,Residential,Tue May 20 00:00:00 EDT 2008,420000,38.271646,-121.286848 5404 ALMOND FALLS WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,425000,38.527502,-121.233492 6306 CONEJO,RANCHO MURIETA,95683,CA,4,2,3192,Residential,Tue May 20 00:00:00 EDT 2008,425000,38.512602,-121.087233 14 CASA VATONI PL,SACRAMENTO,95834,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,433500,38.650221,-121.551704 1456 EAGLESFIELD LN,LINCOLN,95648,CA,4,3,0,Residential,Tue May 20 00:00:00 EDT 2008,436746,38.857635,-121.311375 4100 BOTHWELL CIR,EL DORADO HILLS,95762,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,438700,38.679136,-121.034329 427 21ST ST,SACRAMENTO,95811,CA,2,1,1247,Residential,Tue May 20 00:00:00 EDT 2008,445000,38.582604,-121.47576 1044 GALSTON DR,FOLSOM,95630,CA,4,2,2581,Residential,Tue May 20 00:00:00 EDT 2008,450000,38.676306,-121.09954 4440 SYCAMORE AVE,SACRAMENTO,95841,CA,3,1,2068,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.646374,-121.353658 1032 SOUZA DR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.668239,-121.064437 9760 LAZULITE CT,ELK GROVE,95624,CA,4,3,3992,Residential,Tue May 20 00:00:00 EDT 2008,460000,38.403609,-121.335541 241 LANFRANCO CIR,SACRAMENTO,95835,CA,4,4,3397,Residential,Tue May 20 00:00:00 EDT 2008,465000,38.665696,-121.549437 5559 NORTHBOROUGH DR,SACRAMENTO,95835,CA,5,3,3881,Residential,Tue May 20 00:00:00 EDT 2008,471750,38.677225,-121.519687 2125 BIG SKY DR,ROCKLIN,95765,CA,5,3,0,Residential,Tue May 20 00:00:00 EDT 2008,480000,38.801637,-121.278798 2109 HAMLET PL,CARMICHAEL,95608,CA,2,2,1598,Residential,Tue May 20 00:00:00 EDT 2008,484000,38.602754,-121.329326 9970 STATE HIGHWAY 193,PLACERVILLE,95667,CA,4,3,1929,Residential,Tue May 20 00:00:00 EDT 2008,485000,38.787877,-120.816676 2901 PINTAIL WAY,ELK GROVE,95757,CA,4,3,3070,Residential,Tue May 20 00:00:00 EDT 2008,495000,38.398488,-121.473424 201 FIRESTONE DR,ROSEVILLE,95678,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,500500,38.770153,-121.300039 1740 HIGH ST,AUBURN,95603,CA,3,3,0,Residential,Tue May 20 00:00:00 EDT 2008,504000,38.891935,-121.08434 2733 DANA LOOP,EL DORADO HILLS,95762,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,541000,38.628459,-121.055078 9741 SADDLEBRED CT,WILTON,95693,CA,0,0,0,Residential,Tue May 20 00:00:00 EDT 2008,560000,38.408841,-121.198039 7756 TIGERWOODS DR,SACRAMENTO,95829,CA,5,3,3984,Residential,Tue May 20 00:00:00 EDT 2008,572500,38.47643,-121.309243 5709 RIVER OAK WAY,CARMICHAEL,95608,CA,4,2,2222,Residential,Tue May 20 00:00:00 EDT 2008,582000,38.602461,-121.330979 2981 WRINGER DR,ROSEVILLE,95661,CA,4,3,3838,Residential,Tue May 20 00:00:00 EDT 2008,613401,38.735373,-121.227072 8616 ROCKPORTE CT,ROSEVILLE,95747,CA,4,2,0,Residential,Tue May 20 00:00:00 EDT 2008,614000,38.742118,-121.359909 4128 HILL ST,FAIR OAKS,95628,CA,5,5,2846,Residential,Tue May 20 00:00:00 EDT 2008,680000,38.64167,-121.262099 1409 47TH ST,SACRAMENTO,95819,CA,5,2,2484,Residential,Tue May 20 00:00:00 EDT 2008,699000,38.563244,-121.446876 3935 EL MONTE DR,LOOMIS,95650,CA,4,4,1624,Residential,Tue May 20 00:00:00 EDT 2008,839000,38.813337,-121.133348 5840 WALERGA RD,SACRAMENTO,95842,CA,2,1,840,Condo,Mon May 19 00:00:00 EDT 2008,40000,38.673678,-121.357471 923 FULTON AVE,SACRAMENTO,95825,CA,1,1,484,Condo,Mon May 19 00:00:00 EDT 2008,48000,38.582279,-121.401482 261 REDONDO AVE,SACRAMENTO,95815,CA,3,1,970,Residential,Mon May 19 00:00:00 EDT 2008,61500,38.620685,-121.460539 4030 BROADWAY,SACRAMENTO,95817,CA,2,1,623,Residential,Mon May 19 00:00:00 EDT 2008,62050,38.546798,-121.460038 3660 22ND AVE,SACRAMENTO,95820,CA,2,1,932,Residential,Mon May 19 00:00:00 EDT 2008,65000,38.532718,-121.46747 3924 HIGH ST,SACRAMENTO,95838,CA,2,1,796,Residential,Mon May 19 00:00:00 EDT 2008,65000,38.638797,-121.435049 4734 14TH AVE,SACRAMENTO,95820,CA,2,1,834,Residential,Mon May 19 00:00:00 EDT 2008,68000,38.539447,-121.450858 4734 14TH AVE,SACRAMENTO,95820,CA,2,1,834,Residential,Mon May 19 00:00:00 EDT 2008,68000,38.539447,-121.450858 5050 RHODE ISLAND DR Unit 4,SACRAMENTO,95841,CA,2,1,924,Condo,Mon May 19 00:00:00 EDT 2008,77000,38.658739,-121.333561 4513 GREENHOLME DR,SACRAMENTO,95842,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,82732,38.669104,-121.359008 3845 ELM ST,SACRAMENTO,95838,CA,3,1,1250,Residential,Mon May 19 00:00:00 EDT 2008,84000,38.637337,-121.432835 3908 17TH AVE,SACRAMENTO,95820,CA,2,1,984,Residential,Mon May 19 00:00:00 EDT 2008,84675,38.53728,-121.463531 7109 CHANDLER DR,SACRAMENTO,95828,CA,3,1,1013,Residential,Mon May 19 00:00:00 EDT 2008,85000,38.497237,-121.424187 7541 SKELTON WAY,SACRAMENTO,95822,CA,3,1,1012,Residential,Mon May 19 00:00:00 EDT 2008,90000,38.484274,-121.488851 9058 MONTOYA ST,SACRAMENTO,95826,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,90000,38.559144,-121.368387 1016 CONGRESS AVE,SACRAMENTO,95838,CA,2,2,918,Residential,Mon May 19 00:00:00 EDT 2008,91000,38.630151,-121.442789 540 MORRISON AVE,SACRAMENTO,95838,CA,3,1,1082,Residential,Mon May 19 00:00:00 EDT 2008,95000,38.637704,-121.453946 5303 JERRETT WAY,SACRAMENTO,95842,CA,2,1,964,Residential,Mon May 19 00:00:00 EDT 2008,97500,38.663282,-121.359631 2820 DEL PASO BLVD,SACRAMENTO,95815,CA,4,2,1404,Multi-Family,Mon May 19 00:00:00 EDT 2008,100000,38.617718,-121.440089 3715 TALLYHO DR Unit 78HIGH,SACRAMENTO,95826,CA,1,1,625,Condo,Mon May 19 00:00:00 EDT 2008,100000,38.544627,-121.35796 6013 ROWAN WAY,CITRUS HEIGHTS,95621,CA,2,1,888,Residential,Mon May 19 00:00:00 EDT 2008,101000,38.675893,-121.2963 2987 PONDEROSA LN,SACRAMENTO,95815,CA,4,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,102750,38.622243,-121.457863 3732 LANKERSHIM WAY,NORTH HIGHLANDS,95660,CA,3,1,1331,Residential,Mon May 19 00:00:00 EDT 2008,112500,38.68972,-121.378399 2216 DUNLAP DR,SACRAMENTO,95821,CA,3,1,1014,Residential,Mon May 19 00:00:00 EDT 2008,113000,38.623738,-121.41305 3503 21ST AVE,SACRAMENTO,95820,CA,4,2,1448,Residential,Mon May 19 00:00:00 EDT 2008,114000,38.53361,-121.469308 523 EXCHANGE ST,SACRAMENTO,95838,CA,3,1,966,Residential,Mon May 19 00:00:00 EDT 2008,114000,38.659414,-121.45408 8101 PORT ROYALE WAY,SACRAMENTO,95823,CA,2,1,779,Residential,Mon May 19 00:00:00 EDT 2008,114750,38.463929,-121.438667 8020 WALERGA RD,ANTELOPE,95843,CA,2,2,836,Condo,Mon May 19 00:00:00 EDT 2008,115000,38.71607,-121.364468 167 VALLEY OAK DR,ROSEVILLE,95678,CA,2,2,1100,Condo,Mon May 19 00:00:00 EDT 2008,115000,38.732429,-121.288069 7876 BURLINGTON WAY,SACRAMENTO,95832,CA,3,1,1174,Residential,Mon May 19 00:00:00 EDT 2008,116100,38.470093,-121.468347 3726 JONKO AVE,NORTH HIGHLANDS,95660,CA,3,2,1207,Residential,Mon May 19 00:00:00 EDT 2008,119250,38.656131,-121.377265 7342 GIGI PL,SACRAMENTO,95828,CA,4,4,1995,Multi-Family,Mon May 19 00:00:00 EDT 2008,120000,38.490704,-121.410176 2610 PHYLLIS AVE,SACRAMENTO,95820,CA,2,1,804,Residential,Mon May 19 00:00:00 EDT 2008,120000,38.53105,-121.479574 4200 COMMERCE WAY Unit 711,SACRAMENTO,95834,CA,2,2,958,Condo,Mon May 19 00:00:00 EDT 2008,120000,38.647523,-121.523217 4621 COUNTRY SCENE WAY,SACRAMENTO,95823,CA,3,2,1366,Residential,Mon May 19 00:00:00 EDT 2008,120108,38.470187,-121.448149 5380 VILLAGE WOOD DR,SACRAMENTO,95823,CA,2,2,901,Residential,Mon May 19 00:00:00 EDT 2008,121500,38.454949,-121.440578 2621 EVERGREEN ST,SACRAMENTO,95815,CA,3,1,696,Residential,Mon May 19 00:00:00 EDT 2008,121725,38.613103,-121.444085 201 CARLO CT,GALT,95632,CA,3,2,1080,Residential,Mon May 19 00:00:00 EDT 2008,122000,38.24227,-121.31032 6743 21ST ST,SACRAMENTO,95822,CA,3,2,1104,Residential,Mon May 19 00:00:00 EDT 2008,123000,38.50372,-121.490657 3128 VIA GRANDE,SACRAMENTO,95825,CA,2,1,972,Residential,Mon May 19 00:00:00 EDT 2008,125000,38.598321,-121.39161 2847 BELGRADE WAY,SACRAMENTO,95833,CA,4,2,1390,Residential,Mon May 19 00:00:00 EDT 2008,125573,38.617173,-121.482541 7741 MILLDALE CIR,ELVERTA,95626,CA,4,2,1354,Residential,Mon May 19 00:00:00 EDT 2008,126714,38.705834,-121.43919 9013 CASALS ST,SACRAMENTO,95826,CA,2,1,795,Condo,Mon May 19 00:00:00 EDT 2008,126960,38.557045,-121.37167 227 MAHAN CT Unit 1,ROSEVILLE,95678,CA,2,1,780,Condo,Mon May 19 00:00:00 EDT 2008,127000,38.749723,-121.27008 7349 FLETCHER FARM DR,SACRAMENTO,95828,CA,4,2,1587,Residential,Mon May 19 00:00:00 EDT 2008,127500,38.49069,-121.382619 7226 LARCHMONT DR,NORTH HIGHLANDS,95660,CA,3,2,1209,Residential,Mon May 19 00:00:00 EDT 2008,130000,38.699269,-121.376334 4114 35TH AVE,SACRAMENTO,95824,CA,2,1,1139,Residential,Mon May 19 00:00:00 EDT 2008,133105,38.520941,-121.459355 617 M ST,RIO LINDA,95673,CA,2,2,1690,Residential,Mon May 19 00:00:00 EDT 2008,136500,38.691104,-121.451832 7032 FAIR OAKS BLVD,CARMICHAEL,95608,CA,3,2,1245,Condo,Mon May 19 00:00:00 EDT 2008,139500,38.628563,-121.328297 2421 SANTINA WAY,ELVERTA,95626,CA,3,2,1416,Residential,Mon May 19 00:00:00 EDT 2008,140000,38.71865,-121.407763 2368 CRAIG AVE,SACRAMENTO,95832,CA,3,2,1300,Residential,Mon May 19 00:00:00 EDT 2008,140800,38.47807,-121.48114 2123 AMANDA WAY,SACRAMENTO,95822,CA,3,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,145000,38.484896,-121.486948 7620 DARLA WAY,SACRAMENTO,95828,CA,4,2,1590,Residential,Mon May 19 00:00:00 EDT 2008,147000,38.478502,-121.403517 8344 FIELDPOPPY CIR,SACRAMENTO,95828,CA,3,2,1407,Residential,Mon May 19 00:00:00 EDT 2008,149600,38.479083,-121.400702 3624 20TH AVE,SACRAMENTO,95820,CA,5,2,1516,Residential,Mon May 19 00:00:00 EDT 2008,150000,38.534508,-121.467907 10001 WOODCREEK OAKS BLVD Unit 1415,ROSEVILLE,95747,CA,2,2,0,Condo,Mon May 19 00:00:00 EDT 2008,150000,38.795529,-121.328819 2848 PROVO WAY,SACRAMENTO,95822,CA,3,2,1646,Residential,Mon May 19 00:00:00 EDT 2008,150000,38.489759,-121.474754 6045 EHRHARDT AVE,SACRAMENTO,95823,CA,3,2,1676,Residential,Mon May 19 00:00:00 EDT 2008,155000,38.457157,-121.433065 1223 LAMBERTON CIR,SACRAMENTO,95838,CA,3,2,1370,Residential,Mon May 19 00:00:00 EDT 2008,155435,38.646677,-121.437573 1223 LAMBERTON CIR,SACRAMENTO,95838,CA,3,2,1370,Residential,Mon May 19 00:00:00 EDT 2008,155500,38.646677,-121.437573 6000 BIRCHGLADE WAY,CITRUS HEIGHTS,95621,CA,4,2,1351,Residential,Mon May 19 00:00:00 EDT 2008,158000,38.70166,-121.323249 7204 THOMAS DR,NORTH HIGHLANDS,95660,CA,3,2,1152,Residential,Mon May 19 00:00:00 EDT 2008,158000,38.697898,-121.377687 8363 LANGTREE WAY,SACRAMENTO,95823,CA,3,2,1452,Residential,Mon May 19 00:00:00 EDT 2008,160000,38.45356,-121.435959 1675 VERNON ST Unit 8,ROSEVILLE,95678,CA,2,1,990,Residential,Mon May 19 00:00:00 EDT 2008,160000,38.734136,-121.299639 6632 IBEX WOODS CT,CITRUS HEIGHTS,95621,CA,2,2,1162,Residential,Mon May 19 00:00:00 EDT 2008,164000,38.720868,-121.309855 117 EVCAR WAY,RIO LINDA,95673,CA,3,2,1182,Residential,Mon May 19 00:00:00 EDT 2008,164000,38.687659,-121.4633 6485 LAGUNA MIRAGE LN,ELK GROVE,95758,CA,2,2,1112,Residential,Mon May 19 00:00:00 EDT 2008,165000,38.42465,-121.430137 746 MOOSE CREEK WAY,GALT,95632,CA,3,2,1100,Residential,Mon May 19 00:00:00 EDT 2008,167000,38.283085,-121.302071 8306 CURLEW CT,CITRUS HEIGHTS,95621,CA,4,2,1280,Residential,Mon May 19 00:00:00 EDT 2008,167293,38.715781,-121.298519 8306 CURLEW CT,CITRUS HEIGHTS,95621,CA,4,2,1280,Residential,Mon May 19 00:00:00 EDT 2008,167293,38.715781,-121.298519 5217 ARGO WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Mon May 19 00:00:00 EDT 2008,168000,38.52774,-121.433669 7108 HEATHER TREE DR,SACRAMENTO,95842,CA,3,2,1159,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.695677,-121.36022 2956 DAVENPORT WAY,SACRAMENTO,95833,CA,4,2,1917,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.620687,-121.482619 10062 LINCOLN VILLAGE DR,SACRAMENTO,95827,CA,3,2,1520,Residential,Mon May 19 00:00:00 EDT 2008,170000,38.564,-121.320023 332 PALIN AVE,GALT,95632,CA,3,2,1204,Residential,Mon May 19 00:00:00 EDT 2008,174000,38.260467,-121.302636 4649 FREEWAY CIR,SACRAMENTO,95841,CA,3,2,1120,Residential,Mon May 19 00:00:00 EDT 2008,178000,38.658734,-121.357196 8593 DERLIN WAY,SACRAMENTO,95823,CA,3,2,1436,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.447585,-121.426627 9273 PREMIER WAY,SACRAMENTO,95826,CA,3,2,1451,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.55992,-121.352539 8032 DUSENBERG CT,SACRAMENTO,95828,CA,4,2,1638,Residential,Mon May 19 00:00:00 EDT 2008,180000,38.466499,-121.381119 7110 STELLA LN Unit 15,CARMICHAEL,95608,CA,2,2,1000,Condo,Mon May 19 00:00:00 EDT 2008,182000,38.637396,-121.300055 1786 PIEDMONT WAY,ROSEVILLE,95661,CA,3,1,1152,Residential,Mon May 19 00:00:00 EDT 2008,188325,38.72748,-121.256537 1347 HIDALGO CIR,ROSEVILLE,95747,CA,3,2,1154,Residential,Mon May 19 00:00:00 EDT 2008,191500,38.747878,-121.311279 212 CAPPUCINO WAY,SACRAMENTO,95838,CA,3,2,1353,Residential,Mon May 19 00:00:00 EDT 2008,192000,38.657811,-121.465327 5938 WOODBRIAR WAY,CITRUS HEIGHTS,95621,CA,3,2,1329,Residential,Mon May 19 00:00:00 EDT 2008,192700,38.706152,-121.325399 3801 WILDROSE WAY,SACRAMENTO,95826,CA,3,1,1356,Residential,Mon May 19 00:00:00 EDT 2008,195000,38.544368,-121.369979 508 SAMUEL WAY,SACRAMENTO,95838,CA,3,2,1505,Residential,Mon May 19 00:00:00 EDT 2008,197654,38.645689,-121.452766 6128 CARL SANDBURG CIR,SACRAMENTO,95842,CA,3,1,1009,Residential,Mon May 19 00:00:00 EDT 2008,198000,38.681541,-121.355616 1 KENNELFORD CIR,SACRAMENTO,95823,CA,3,2,1144,Residential,Mon May 19 00:00:00 EDT 2008,200345,38.46452,-121.427606 909 SINGINGWOOD RD,SACRAMENTO,95864,CA,2,1,930,Residential,Mon May 19 00:00:00 EDT 2008,203000,38.581471,-121.38839 6671 FOXWOOD CT,SACRAMENTO,95841,CA,4,2,1766,Residential,Mon May 19 00:00:00 EDT 2008,207000,38.687943,-121.328883 8165 AYN RAND CT,SACRAMENTO,95828,CA,4,3,1940,Residential,Mon May 19 00:00:00 EDT 2008,208000,38.468639,-121.403265 9474 VILLAGE TREE DR,ELK GROVE,95758,CA,4,2,1776,Residential,Mon May 19 00:00:00 EDT 2008,210000,38.413947,-121.408276 7213 CALVIN DR,CITRUS HEIGHTS,95621,CA,3,1,1258,Residential,Mon May 19 00:00:00 EDT 2008,212000,38.698154,-121.298375 8167 DERBY PARK CT,SACRAMENTO,95828,CA,4,2,1872,Residential,Mon May 19 00:00:00 EDT 2008,213675,38.460492,-121.373379 6344 LAGUNA MIRAGE LN,ELK GROVE,95758,CA,2,2,1112,Residential,Mon May 19 00:00:00 EDT 2008,213697,38.423963,-121.428875 2945 RED HAWK WAY,SACRAMENTO,95833,CA,4,2,1856,Residential,Mon May 19 00:00:00 EDT 2008,215000,38.619675,-121.496903 3228 I ST,SACRAMENTO,95816,CA,4,3,1939,Residential,Mon May 19 00:00:00 EDT 2008,215000,38.573844,-121.462839 308 ATKINSON ST,ROSEVILLE,95678,CA,3,1,998,Residential,Mon May 19 00:00:00 EDT 2008,215100,38.746794,-121.29971 624 HOVEY WAY,ROSEVILLE,95678,CA,3,2,1758,Residential,Mon May 19 00:00:00 EDT 2008,217500,38.756149,-121.306479 110 COPPER LEAF WAY,SACRAMENTO,95838,CA,3,2,2142,Residential,Mon May 19 00:00:00 EDT 2008,218000,38.658466,-121.460661 7535 ALMA VISTA WAY,SACRAMENTO,95831,CA,2,1,950,Residential,Mon May 19 00:00:00 EDT 2008,220000,38.48403,-121.507641 7423 WILSALL CT,ELK GROVE,95758,CA,4,3,1739,Residential,Mon May 19 00:00:00 EDT 2008,221000,38.417026,-121.416821 8629 VIA ALTA WAY,ELK GROVE,95624,CA,3,2,1516,Residential,Mon May 19 00:00:00 EDT 2008,222900,38.398245,-121.380615 3318 DAVIDSON DR,ANTELOPE,95843,CA,3,1,988,Residential,Mon May 19 00:00:00 EDT 2008,223139,38.705753,-121.388917 913 COBDEN CT,GALT,95632,CA,4,2,1555,Residential,Mon May 19 00:00:00 EDT 2008,225500,38.282001,-121.295902 4419 79TH ST,SACRAMENTO,95820,CA,3,2,1212,Residential,Mon May 19 00:00:00 EDT 2008,228327,38.534827,-121.412545 3012 SPOONWOOD WAY,SACRAMENTO,95833,CA,4,2,1871,Residential,Mon May 19 00:00:00 EDT 2008,230000,38.62478,-121.523474 8728 CRYSTAL RIVER WAY,SACRAMENTO,95828,CA,3,2,1302,Residential,Mon May 19 00:00:00 EDT 2008,230000,38.47547,-121.380055 4709 AMBER LN Unit 1,SACRAMENTO,95841,CA,2,1,756,Condo,Mon May 19 00:00:00 EDT 2008,230522,38.657789,-121.354994 4508 OLD DAIRY DR,ANTELOPE,95843,CA,4,3,2026,Residential,Mon May 19 00:00:00 EDT 2008,231200,38.72286,-121.358939 312 RIVER ISLE WAY,SACRAMENTO,95831,CA,3,2,1375,Residential,Mon May 19 00:00:00 EDT 2008,232000,38.49026,-121.550527 301 OLIVADI WAY,SACRAMENTO,95834,CA,2,2,1250,Condo,Mon May 19 00:00:00 EDT 2008,232500,38.644406,-121.549049 5636 25TH ST,SACRAMENTO,95822,CA,3,1,1058,Residential,Mon May 19 00:00:00 EDT 2008,233641,38.523828,-121.481139 8721 SPRUCE RIDGE WAY,ANTELOPE,95843,CA,3,2,1187,Residential,Mon May 19 00:00:00 EDT 2008,234000,38.727657,-121.391028 7461 WINDBRIDGE DR,SACRAMENTO,95831,CA,2,2,1324,Residential,Mon May 19 00:00:00 EDT 2008,234500,38.48797,-121.530229 8101 LEMON COVE CT,SACRAMENTO,95828,CA,4,3,1936,Residential,Mon May 19 00:00:00 EDT 2008,235000,38.462981,-121.408288 10949 SCOTSMAN WAY,RANCHO CORDOVA,95670,CA,5,4,2382,Multi-Family,Mon May 19 00:00:00 EDT 2008,236000,38.603686,-121.277844 617 WILLOW CREEK DR,FOLSOM,95630,CA,3,2,1427,Residential,Mon May 19 00:00:00 EDT 2008,236073,38.679626,-121.142609 3301 PARK DR Unit 1914,SACRAMENTO,95835,CA,3,2,1678,Condo,Mon May 19 00:00:00 EDT 2008,238000,38.665296,-121.531993 709 CIMMARON CT,GALT,95632,CA,4,2,1798,Residential,Mon May 19 00:00:00 EDT 2008,238861,38.277177,-121.303747 3305 RIO ROCA CT,ANTELOPE,95843,CA,4,3,2652,Residential,Mon May 19 00:00:00 EDT 2008,239700,38.725079,-121.387698 9080 BEDROCK CT,SACRAMENTO,95829,CA,4,2,1816,Residential,Mon May 19 00:00:00 EDT 2008,240000,38.456939,-121.362965 100 TOURMALINE CIR,SACRAMENTO,95834,CA,5,3,3076,Residential,Mon May 19 00:00:00 EDT 2008,240000,38.63437,-121.510779 6411 RED BIRCH WAY,ELK GROVE,95758,CA,4,2,1844,Residential,Mon May 19 00:00:00 EDT 2008,241000,38.43461,-121.429316 4867 LAGUNA DR,SACRAMENTO,95823,CA,3,2,1306,Residential,Mon May 19 00:00:00 EDT 2008,245000,38.46179,-121.445371 3662 RIVER DR,SACRAMENTO,95833,CA,4,3,2447,Residential,Mon May 19 00:00:00 EDT 2008,246000,38.604969,-121.54255 6943 WOLFGRAM WAY,SACRAMENTO,95828,CA,4,2,1176,Residential,Mon May 19 00:00:00 EDT 2008,247234,38.489215,-121.419546 77 RINETTI WAY,RIO LINDA,95673,CA,4,2,1182,Residential,Mon May 19 00:00:00 EDT 2008,247480,38.687021,-121.463151 1316 I ST,RIO LINDA,95673,CA,3,1,1160,Residential,Mon May 19 00:00:00 EDT 2008,249862,38.683674,-121.435204 2130 CATHERWOOD WAY,SACRAMENTO,95835,CA,3,2,1424,Residential,Mon May 19 00:00:00 EDT 2008,251000,38.675506,-121.510987 8304 JUGLANS DR,ORANGEVALE,95662,CA,4,2,1574,Residential,Mon May 19 00:00:00 EDT 2008,252155,38.691829,-121.249033 5308 MARBURY WAY,ANTELOPE,95843,CA,3,2,1830,Residential,Mon May 19 00:00:00 EDT 2008,254172,38.710221,-121.341707 9182 LAKEMONT DR,ELK GROVE,95624,CA,4,2,1724,Residential,Mon May 19 00:00:00 EDT 2008,258000,38.451353,-121.358776 2231 COUNTRY VILLA CT,AUBURN,95603,CA,2,2,1255,Condo,Mon May 19 00:00:00 EDT 2008,260000,38.931671,-121.097862 8491 CRYSTAL WALK CIR,ELK GROVE,95758,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.416916,-121.407554 361 MAHONIA CIR,SACRAMENTO,95835,CA,4,3,2175,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.676172,-121.509761 3427 LA CADENA WAY,SACRAMENTO,95835,CA,4,2,1904,Residential,Mon May 19 00:00:00 EDT 2008,261000,38.681194,-121.537351 955 BIG SUR CT,EL DORADO HILLS,95762,CA,4,2,1808,Residential,Mon May 19 00:00:00 EDT 2008,262500,38.664347,-121.076529 11826 DIONYSUS WAY,RANCHO CORDOVA,95742,CA,4,2,2711,Residential,Mon May 19 00:00:00 EDT 2008,266000,38.551046,-121.239411 5847 DEL CAMPO LN,CARMICHAEL,95608,CA,3,1,1713,Residential,Mon May 19 00:00:00 EDT 2008,266000,38.671995,-121.324339 5635 FOXVIEW WAY,ELK GROVE,95757,CA,3,2,1457,Residential,Mon May 19 00:00:00 EDT 2008,270000,38.395256,-121.438249 10372 VIA CINTA CT,ELK GROVE,95757,CA,4,3,2724,Residential,Mon May 19 00:00:00 EDT 2008,274425,38.380089,-121.428186 6286 LONETREE BLVD,ROCKLIN,95765,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,274500,38.805036,-121.293608 7744 SOUTHBREEZE DR,SACRAMENTO,95828,CA,3,2,1468,Residential,Mon May 19 00:00:00 EDT 2008,275336,38.476932,-121.378349 2242 ABLE WAY,SACRAMENTO,95835,CA,4,3,2550,Residential,Mon May 19 00:00:00 EDT 2008,277980,38.666074,-121.509743 1042 STARBROOK DR,GALT,95632,CA,4,2,1928,Residential,Mon May 19 00:00:00 EDT 2008,280000,38.285611,-121.293063 1219 G ST,SACRAMENTO,95814,CA,3,3,1922,Residential,Mon May 19 00:00:00 EDT 2008,284686,38.582818,-121.489096 6220 OPUS CT,CITRUS HEIGHTS,95621,CA,3,2,1343,Residential,Mon May 19 00:00:00 EDT 2008,284893,38.715853,-121.317095 5419 HAVENHURST CIR,ROCKLIN,95677,CA,3,2,1510,Residential,Mon May 19 00:00:00 EDT 2008,285000,38.786746,-121.209957 220 OLD AIRPORT RD,AUBURN,95603,CA,2,2,960,Multi-Family,Mon May 19 00:00:00 EDT 2008,285000,38.939802,-121.054575 4622 MEYER WAY,CARMICHAEL,95608,CA,4,2,1559,Residential,Mon May 19 00:00:00 EDT 2008,285000,38.64913,-121.310667 4885 SUMMIT VIEW DR,EL DORADO,95623,CA,3,2,1624,Residential,Mon May 19 00:00:00 EDT 2008,289000,38.673285,-120.879176 26 JEANROSS CT,SACRAMENTO,95832,CA,5,3,2992,Residential,Mon May 19 00:00:00 EDT 2008,295000,38.473162,-121.491085 4800 MAPLEPLAIN AVE,ELK GROVE,95758,CA,4,2,2109,Residential,Mon May 19 00:00:00 EDT 2008,296000,38.432848,-121.449237 10629 BASIE WAY,RANCHO CORDOVA,95670,CA,4,2,1524,Residential,Mon May 19 00:00:00 EDT 2008,296056,38.579,-121.292627 8612 WILLOW GROVE WAY,SACRAMENTO,95828,CA,3,2,1248,Residential,Mon May 19 00:00:00 EDT 2008,297359,38.464994,-121.386962 62 DE FER CIR,SACRAMENTO,95823,CA,4,2,1876,Residential,Mon May 19 00:00:00 EDT 2008,299940,38.49254,-121.463316 2513 OLD KENMARE RD,LINCOLN,95648,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,304000,38.847396,-121.259586 3253 ABOTO WAY,RANCHO CORDOVA,95670,CA,4,3,1851,Residential,Mon May 19 00:00:00 EDT 2008,305000,38.57727,-121.285591 3072 VILLAGE PLAZA DR,ROSEVILLE,95747,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,307000,38.773094,-121.365905 251 CHANGO CIR,SACRAMENTO,95835,CA,4,2,2218,Residential,Mon May 19 00:00:00 EDT 2008,311328,38.68237,-121.539147 8205 WEYBURN CT,SACRAMENTO,95828,CA,3,2,1394,Residential,Mon May 19 00:00:00 EDT 2008,313138,38.47316,-121.403893 8788 LA MARGARITA WAY,SACRAMENTO,95828,CA,3,2,1410,Residential,Mon May 19 00:00:00 EDT 2008,316630,38.468185,-121.375694 5912 DEEPDALE WAY,ELK GROVE,95758,CA,5,3,3468,Residential,Mon May 19 00:00:00 EDT 2008,320000,38.439565,-121.436606 4712 PISMO BEACH DR,ANTELOPE,95843,CA,5,3,2346,Residential,Mon May 19 00:00:00 EDT 2008,320000,38.707705,-121.354153 4741 PACIFIC PARK DR,ANTELOPE,95843,CA,5,3,2347,Residential,Mon May 19 00:00:00 EDT 2008,325000,38.709299,-121.353056 310 GROTH CIR,SACRAMENTO,95834,CA,4,2,1659,Residential,Mon May 19 00:00:00 EDT 2008,328578,38.638764,-121.531827 6121 WILD FOX CT,ELK GROVE,95757,CA,3,3,2442,Residential,Mon May 19 00:00:00 EDT 2008,331000,38.406758,-121.431669 12241 CANYONLANDS DR,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,331500,38.557293,-121.217611 29 COOL FOUNTAIN CT,SACRAMENTO,95833,CA,4,2,2155,Residential,Mon May 19 00:00:00 EDT 2008,340000,38.606906,-121.54132 907 RIO ROBLES AVE,SACRAMENTO,95838,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,344755,38.664765,-121.445006 8909 BILLFISH WAY,SACRAMENTO,95828,CA,3,2,1810,Residential,Mon May 19 00:00:00 EDT 2008,345746,38.475433,-121.372584 6232 GUS WAY,ELK GROVE,95757,CA,4,2,2789,Residential,Mon May 19 00:00:00 EDT 2008,351000,38.388129,-121.43117 200 OAKWILDE ST,GALT,95632,CA,4,2,1606,Residential,Mon May 19 00:00:00 EDT 2008,353767,38.2535,-121.31812 1033 PARK STREAM DR,GALT,95632,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,355000,38.287785,-121.289903 200 ALLAIRE CIR,SACRAMENTO,95835,CA,4,2,2166,Residential,Mon May 19 00:00:00 EDT 2008,356035,38.68318,-121.53484 1322 SUTTER WALK,SACRAMENTO,95816,CA,0,0,0,Condo,Mon May 19 00:00:00 EDT 2008,360000,38.53805,-121.5047 5479 NICKMAN WAY,SACRAMENTO,95835,CA,4,2,1871,Residential,Mon May 19 00:00:00 EDT 2008,360552,38.672966,-121.502748 2103 BURBERRY WAY,SACRAMENTO,95835,CA,3,2,1800,Residential,Mon May 19 00:00:00 EDT 2008,362305,38.67342,-121.508542 2450 SAN JOSE WAY,SACRAMENTO,95817,CA,3,1,1683,Residential,Mon May 19 00:00:00 EDT 2008,365000,38.553596,-121.459483 7641 ROSEHALL DR,ROSEVILLE,95678,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,367554,38.791617,-121.286147 1336 LAYSAN TEAL DR,ROSEVILLE,95747,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,368500,38.796121,-121.319963 2802 BLACK OAK DR,ROCKLIN,95765,CA,2,2,1596,Residential,Mon May 19 00:00:00 EDT 2008,370000,38.837006,-121.232024 2113 FALL TRAIL CT,PLACERVILLE,95667,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,371086,38.733155,-120.748039 10112 LAMBEAU CT,ELK GROVE,95757,CA,3,2,1179,Residential,Mon May 19 00:00:00 EDT 2008,378000,38.390328,-121.448022 6313 CASTRO VERDE WAY,ELK GROVE,95757,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,383000,38.381102,-121.42901 3622 CURTIS DR,SACRAMENTO,95818,CA,3,1,1639,Residential,Mon May 19 00:00:00 EDT 2008,388000,38.541735,-121.480098 11817 OPAL RIDGE WAY,RANCHO CORDOVA,95742,CA,5,3,3281,Residential,Mon May 19 00:00:00 EDT 2008,395100,38.551083,-121.237476 170 LAGOMARSINO WAY,SACRAMENTO,95819,CA,3,2,1697,Residential,Mon May 19 00:00:00 EDT 2008,400000,38.574894,-121.435806 2743 DEAKIN PL,EL DORADO HILLS,95762,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,400000,38.69288,-121.073551 3361 ALDER CANYON WAY,ANTELOPE,95843,CA,4,3,2085,Residential,Mon May 19 00:00:00 EDT 2008,408431,38.727649,-121.385656 2148 RANCH VIEW DR,ROCKLIN,95765,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,413000,38.837455,-121.289337 398 LINDLEY DR,SACRAMENTO,95815,CA,4,2,1744,Multi-Family,Mon May 19 00:00:00 EDT 2008,416767,38.622359,-121.457582 3013 BRIDLEWOOD DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Mon May 19 00:00:00 EDT 2008,420000,38.675519,-121.015862 169 BAURER CIR,FOLSOM,95630,CA,4,3,1939,Residential,Mon May 19 00:00:00 EDT 2008,423000,38.66695,-121.120729 2809 LOON CT,CAMERON PARK,95682,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,423000,38.687072,-121.004729 1315 KONDOS AVE,SACRAMENTO,95814,CA,2,3,1788,Residential,Mon May 19 00:00:00 EDT 2008,427500,38.571943,-121.492106 4966 CHARTER RD,ROCKLIN,95765,CA,3,2,1691,Residential,Mon May 19 00:00:00 EDT 2008,430922,38.82553,-121.254698 9516 LAGUNA LAKE WAY,ELK GROVE,95758,CA,4,2,2002,Residential,Mon May 19 00:00:00 EDT 2008,445000,38.411258,-121.431348 5201 BLOSSOM RANCH DR,ELK GROVE,95757,CA,4,4,4303,Residential,Mon May 19 00:00:00 EDT 2008,450000,38.399436,-121.444041 3027 PALMATE WAY,SACRAMENTO,95834,CA,5,3,4246,Residential,Mon May 19 00:00:00 EDT 2008,452000,38.628955,-121.529269 500 WINCHESTER CT,ROSEVILLE,95661,CA,3,2,2274,Residential,Mon May 19 00:00:00 EDT 2008,470000,38.73988,-121.248929 5746 GELSTON WAY,EL DORADO HILLS,95762,CA,4,3,0,Residential,Mon May 19 00:00:00 EDT 2008,471000,38.677015,-121.034083 6935 ELM TREE LN,ORANGEVALE,95662,CA,4,4,3056,Residential,Mon May 19 00:00:00 EDT 2008,475000,38.693041,-121.23294 9605 GOLF COURSE LN,ELK GROVE,95758,CA,3,3,2503,Residential,Mon May 19 00:00:00 EDT 2008,484500,38.409689,-121.446059 719 BAYWOOD CT,EL DORADO HILLS,95762,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,487500,38.647598,-121.077801 5954 TANUS CIR,ROCKLIN,95677,CA,3,3,0,Residential,Mon May 19 00:00:00 EDT 2008,488750,38.777585,-121.2036 100 CHELSEA CT,FOLSOM,95630,CA,3,2,1905,Residential,Mon May 19 00:00:00 EDT 2008,500000,38.69435,-121.177259 1500 ORANGE HILL LN,PENRYN,95663,CA,3,2,1320,Residential,Mon May 19 00:00:00 EDT 2008,506688,38.862708,-121.162092 408 KIRKWOOD CT,LINCOLN,95648,CA,2,2,0,Residential,Mon May 19 00:00:00 EDT 2008,512000,38.861615,-121.26869 1732 TUSCAN GROVE CIR,ROSEVILLE,95747,CA,5,3,0,Residential,Mon May 19 00:00:00 EDT 2008,520000,38.796683,-121.342555 2049 EMPIRE MINE CIR,GOLD RIVER,95670,CA,4,2,3037,Residential,Mon May 19 00:00:00 EDT 2008,528000,38.629299,-121.249021 9360 MAGOS RD,WILTON,95693,CA,5,2,3741,Residential,Mon May 19 00:00:00 EDT 2008,579093,38.416809,-121.240628 104 CATLIN CT,FOLSOM,95630,CA,4,3,2660,Residential,Mon May 19 00:00:00 EDT 2008,636000,38.684459,-121.145935 4734 GIBBONS DR,CARMICHAEL,95608,CA,4,3,3357,Residential,Mon May 19 00:00:00 EDT 2008,668365,38.63558,-121.353639 4629 DORCHESTER LN,GRANITE BAY,95746,CA,5,3,2896,Residential,Mon May 19 00:00:00 EDT 2008,676200,38.723545,-121.216025 2400 COUNTRYSIDE DR,PLACERVILLE,95667,CA,3,2,2025,Residential,Mon May 19 00:00:00 EDT 2008,677048,38.737452,-120.910963 12901 FURLONG DR,WILTON,95693,CA,5,3,3788,Residential,Mon May 19 00:00:00 EDT 2008,691659,38.413535,-121.188211 6222 CALLE MONTALVO CIR,GRANITE BAY,95746,CA,5,3,3670,Residential,Mon May 19 00:00:00 EDT 2008,760000,38.779435,-121.146676 20 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885327,-121.289412 24 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885132,-121.289405 28 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884936,-121.289397 32 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884741,-121.28939 36 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884599,-121.289406 40 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884535,-121.289619 44 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88459,-121.289835 48 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884667,-121.289896 52 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88478,-121.289911 68 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885236,-121.289928 72 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88535,-121.289926 76 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885464,-121.289922 80 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885578,-121.289919 84 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885692,-121.289915 88 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885806,-121.289911 92 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88592,-121.289908 96 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886024,-121.289859 100 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886091,-121.289744 434 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88653,-121.289406 3 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884692,-121.290288 11 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884879,-121.290257 19 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885017,-121.290262 27 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885173,-121.29027 35 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885328,-121.290275 43 E ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885483,-121.290277 51 E ST,LINCOLN,95648,CA,4,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885638,-121.290279 59 E ST,LINCOLN,95648,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885794,-121.290281 75 E ST,LINCOLN,95648,CA,3,2,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886104,-121.290285 63 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885093,-121.289932 398 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88653,-121.288952 386 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886528,-121.288869 374 1ST ST,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886525,-121.288787 116 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289586 108 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289646 100 CRYSTALWOOD WAY,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886282,-121.289706 55 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884865,-121.289922 51 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884752,-121.289907 47 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884638,-121.289893 43 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884568,-121.289784 39 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884546,-121.289562 35 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884645,-121.289397 31 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.88479,-121.289392 27 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.884985,-121.289399 23 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885181,-121.289406 19 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885376,-121.289414 15 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885571,-121.289421 7 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885962,-121.289436 7 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.885962,-121.289436 3 CRYSTALWOOD CIR,LINCOLN,95648,CA,0,0,0,Residential,Mon May 19 00:00:00 EDT 2008,4897,38.886093,-121.289584 8208 WOODYARD WAY,CITRUS HEIGHTS,95621,CA,3,2,1166,Residential,Fri May 16 00:00:00 EDT 2008,30000,38.715322,-121.314787 113 RINETTI WAY,RIO LINDA,95673,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,30000,38.687172,-121.463933 15 LOORZ CT,SACRAMENTO,95823,CA,2,1,838,Residential,Fri May 16 00:00:00 EDT 2008,55422,38.471646,-121.435158 5805 DOTMAR WAY,NORTH HIGHLANDS,95660,CA,2,1,904,Residential,Fri May 16 00:00:00 EDT 2008,63000,38.672642,-121.380343 2332 CAMBRIDGE ST,SACRAMENTO,95815,CA,2,1,1032,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.608085,-121.449651 3812 BELDEN ST,SACRAMENTO,95838,CA,2,1,904,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.636833,-121.44164 3348 40TH ST,SACRAMENTO,95817,CA,2,1,1080,Residential,Fri May 16 00:00:00 EDT 2008,65000,38.544162,-121.460652 127 QUASAR CIR,SACRAMENTO,95822,CA,2,2,990,Residential,Fri May 16 00:00:00 EDT 2008,66500,38.493504,-121.475304 3812 CYPRESS ST,SACRAMENTO,95838,CA,2,1,900,Residential,Fri May 16 00:00:00 EDT 2008,71000,38.636877,-121.444948 5821 64TH ST,SACRAMENTO,95824,CA,2,1,861,Residential,Fri May 16 00:00:00 EDT 2008,75000,38.521202,-121.428146 8248 CENTER PKWY,SACRAMENTO,95823,CA,2,1,906,Condo,Fri May 16 00:00:00 EDT 2008,77000,38.459002,-121.428794 1171 SONOMA AVE,SACRAMENTO,95815,CA,2,1,1011,Residential,Fri May 16 00:00:00 EDT 2008,85000,38.6238,-121.439872 4250 ARDWELL WAY,SACRAMENTO,95823,CA,3,2,1089,Residential,Fri May 16 00:00:00 EDT 2008,95625,38.466938,-121.455631 3104 CLAY ST,SACRAMENTO,95815,CA,2,1,832,Residential,Fri May 16 00:00:00 EDT 2008,96140,38.62391,-121.439208 6063 LAND PARK DR,SACRAMENTO,95822,CA,2,1,800,Condo,Fri May 16 00:00:00 EDT 2008,104250,38.517029,-121.513809 4738 OAKHOLLOW DR,SACRAMENTO,95842,CA,4,2,1292,Residential,Fri May 16 00:00:00 EDT 2008,105000,38.679598,-121.356035 1401 STERLING ST,SACRAMENTO,95822,CA,2,1,810,Residential,Fri May 16 00:00:00 EDT 2008,108000,38.520319,-121.504727 3715 DIDCOT CIR,SACRAMENTO,95838,CA,4,2,1064,Residential,Fri May 16 00:00:00 EDT 2008,109000,38.635232,-121.460098 2426 RASHAWN DR,RANCHO CORDOVA,95670,CA,2,1,911,Residential,Fri May 16 00:00:00 EDT 2008,115000,38.610852,-121.273278 4800 WESTLAKE PKWY Unit 410,SACRAMENTO,95835,CA,1,1,846,Condo,Fri May 16 00:00:00 EDT 2008,115000,38.658812,-121.542345 3409 VIRGO ST,SACRAMENTO,95827,CA,3,2,1320,Residential,Fri May 16 00:00:00 EDT 2008,115500,38.563402,-121.327747 1110 PINEDALE AVE,SACRAMENTO,95838,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,115620,38.660173,-121.440216 2361 LA LOMA DR,RANCHO CORDOVA,95670,CA,3,2,1115,Residential,Fri May 16 00:00:00 EDT 2008,116000,38.59368,-121.316054 1455 64TH AVE,SACRAMENTO,95822,CA,3,2,1169,Residential,Fri May 16 00:00:00 EDT 2008,122000,38.492177,-121.503392 7328 SPRINGMAN ST,SACRAMENTO,95822,CA,3,2,1164,Residential,Fri May 16 00:00:00 EDT 2008,122500,38.491991,-121.477636 119 SAINT MARIE CIR,SACRAMENTO,95823,CA,4,2,1341,Residential,Fri May 16 00:00:00 EDT 2008,123000,38.481454,-121.446644 12 COSTA BRASE CT,SACRAMENTO,95838,CA,3,2,1219,Residential,Fri May 16 00:00:00 EDT 2008,124000,38.655554,-121.464275 6813 SCOTER WAY,SACRAMENTO,95842,CA,4,2,1127,Residential,Fri May 16 00:00:00 EDT 2008,124000,38.69043,-121.361035 6548 GRAYLOCK LN,NORTH HIGHLANDS,95660,CA,3,2,1272,Residential,Fri May 16 00:00:00 EDT 2008,124413,38.686061,-121.369949 1630 GLIDDEN AVE,SACRAMENTO,95822,CA,4,2,1253,Residential,Fri May 16 00:00:00 EDT 2008,125000,38.482717,-121.499683 7825 DALEWOODS WAY,SACRAMENTO,95828,CA,3,2,1120,Residential,Fri May 16 00:00:00 EDT 2008,130000,38.477297,-121.411513 4073 TRESLER AVE,NORTH HIGHLANDS,95660,CA,2,2,1118,Residential,Fri May 16 00:00:00 EDT 2008,131750,38.659016,-121.370457 4288 DYMIC WAY,SACRAMENTO,95838,CA,4,3,1890,Residential,Fri May 16 00:00:00 EDT 2008,137721,38.646541,-121.441139 1158 SAN IGNACIO WAY,SACRAMENTO,95833,CA,3,2,1260,Residential,Fri May 16 00:00:00 EDT 2008,137760,38.623045,-121.486279 4904 J PKWY,SACRAMENTO,95823,CA,3,2,1400,Residential,Fri May 16 00:00:00 EDT 2008,138000,38.487297,-121.44295 2931 HOWE AVE,SACRAMENTO,95821,CA,3,1,1264,Residential,Fri May 16 00:00:00 EDT 2008,140000,38.619012,-121.415329 5531 JANSEN DR,SACRAMENTO,95824,CA,3,1,1060,Residential,Fri May 16 00:00:00 EDT 2008,145000,38.522015,-121.438713 7836 ORCHARD WOODS CIR,SACRAMENTO,95828,CA,2,2,1132,Residential,Fri May 16 00:00:00 EDT 2008,145000,38.47955,-121.410867 4055 DEERBROOK DR,SACRAMENTO,95823,CA,3,2,1466,Residential,Fri May 16 00:00:00 EDT 2008,150000,38.472117,-121.459589 9937 BURLINE ST,SACRAMENTO,95827,CA,3,2,1092,Residential,Fri May 16 00:00:00 EDT 2008,150000,38.559641,-121.32316 6948 MIRADOR WAY,SACRAMENTO,95828,CA,4,2,1628,Residential,Fri May 16 00:00:00 EDT 2008,151000,38.493484,-121.42035 4909 RUGER CT,SACRAMENTO,95842,CA,3,2,960,Residential,Fri May 16 00:00:00 EDT 2008,155000,38.68747,-121.349234 7204 KERSTEN ST,CITRUS HEIGHTS,95621,CA,3,2,1075,Residential,Fri May 16 00:00:00 EDT 2008,155800,38.695863,-121.300814 3150 ROSEMONT DR,SACRAMENTO,95826,CA,3,2,1428,Residential,Fri May 16 00:00:00 EDT 2008,156142,38.554927,-121.35521 8200 STEINBECK WAY,SACRAMENTO,95828,CA,4,2,1358,Residential,Fri May 16 00:00:00 EDT 2008,158000,38.474854,-121.404726 8198 STEVENSON AVE,SACRAMENTO,95828,CA,6,4,2475,Multi-Family,Fri May 16 00:00:00 EDT 2008,159900,38.465271,-121.40426 6824 OLIVE TREE WAY,CITRUS HEIGHTS,95610,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,160000,38.689239,-121.267737 3536 SUN MAIDEN WAY,ANTELOPE,95843,CA,3,2,1711,Residential,Fri May 16 00:00:00 EDT 2008,161500,38.70968,-121.382328 4517 OLYMPIAD WAY,SACRAMENTO,95826,CA,4,2,1483,Residential,Fri May 16 00:00:00 EDT 2008,161600,38.536751,-121.359154 925 COBDEN CT,GALT,95632,CA,3,2,1140,Residential,Fri May 16 00:00:00 EDT 2008,162000,38.282047,-121.295812 8225 SCOTTSDALE DR,SACRAMENTO,95828,CA,4,2,1549,Residential,Fri May 16 00:00:00 EDT 2008,165000,38.487864,-121.402476 8758 LEMAS RD,SACRAMENTO,95828,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,165000,38.467487,-121.377055 6121 ALPINESPRING WAY,ELK GROVE,95758,CA,3,2,1240,Residential,Fri May 16 00:00:00 EDT 2008,167293,38.434075,-121.432623 5937 YORK GLEN WAY,SACRAMENTO,95842,CA,5,2,1712,Residential,Fri May 16 00:00:00 EDT 2008,168000,38.677003,-121.354454 6417 SUNNYFIELD WAY,SACRAMENTO,95823,CA,4,2,1580,Residential,Fri May 16 00:00:00 EDT 2008,168000,38.449153,-121.428272 4008 GREY LIVERY WAY,ANTELOPE,95843,CA,3,2,1669,Residential,Fri May 16 00:00:00 EDT 2008,168750,38.71846,-121.370862 8920 ROSETTA CIR,SACRAMENTO,95826,CA,3,1,1029,Residential,Fri May 16 00:00:00 EDT 2008,168750,38.544374,-121.370874 8300 LICHEN DR,CITRUS HEIGHTS,95621,CA,3,1,1103,Residential,Fri May 16 00:00:00 EDT 2008,170000,38.71641,-121.306239 8884 AMBERJACK WAY,SACRAMENTO,95828,CA,3,2,2161,Residential,Fri May 16 00:00:00 EDT 2008,170250,38.479343,-121.372553 4480 VALLEY HI DR,SACRAMENTO,95823,CA,3,2,1650,Residential,Fri May 16 00:00:00 EDT 2008,173000,38.466781,-121.450955 2250 FOREBAY RD,POLLOCK PINES,95726,CA,3,1,1320,Residential,Fri May 16 00:00:00 EDT 2008,175000,38.77491,-120.597599 3529 FABERGE WAY,SACRAMENTO,95826,CA,3,2,1200,Residential,Fri May 16 00:00:00 EDT 2008,176095,38.553275,-121.346218 1792 DAWNELLE WAY,SACRAMENTO,95835,CA,3,2,1170,Residential,Fri May 16 00:00:00 EDT 2008,176250,38.68271,-121.501697 7800 TABARE CT,CITRUS HEIGHTS,95621,CA,3,2,1199,Residential,Fri May 16 00:00:00 EDT 2008,178000,38.70799,-121.302979 8531 HERMITAGE WAY,SACRAMENTO,95823,CA,4,2,1695,Residential,Fri May 16 00:00:00 EDT 2008,179000,38.448452,-121.428536 2421 BERRYWOOD DR,RANCHO CORDOVA,95670,CA,3,2,1157,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.60868,-121.27849 1005 MORENO WAY,SACRAMENTO,95838,CA,3,2,1410,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.646206,-121.442767 1675 VERNON ST Unit 24,ROSEVILLE,95678,CA,3,2,1174,Residential,Fri May 16 00:00:00 EDT 2008,180000,38.734136,-121.299639 24 WINDCHIME CT,SACRAMENTO,95823,CA,3,2,1593,Residential,Fri May 16 00:00:00 EDT 2008,181000,38.44617,-121.427824 540 HARLING CT,RIO LINDA,95673,CA,3,2,1093,Residential,Fri May 16 00:00:00 EDT 2008,182000,38.68279,-121.453509 1207 CRESCENDO DR,ROSEVILLE,95678,CA,3,2,1770,Residential,Fri May 16 00:00:00 EDT 2008,182587,38.72446,-121.292829 7577 EDDYLEE WAY,SACRAMENTO,95822,CA,4,2,1436,Residential,Fri May 16 00:00:00 EDT 2008,185074,38.48291,-121.491509 8369 FOPPIANO WAY,SACRAMENTO,95829,CA,3,2,1124,Residential,Fri May 16 00:00:00 EDT 2008,185833,38.453839,-121.357919 8817 SAWTELLE WAY,SACRAMENTO,95826,CA,4,2,1139,Residential,Fri May 16 00:00:00 EDT 2008,186785,38.565322,-121.374251 1910 BONAVISTA WAY,SACRAMENTO,95832,CA,3,2,1638,Residential,Fri May 16 00:00:00 EDT 2008,187000,38.476048,-121.494961 8 TIDE CT,SACRAMENTO,95833,CA,3,2,1328,Residential,Fri May 16 00:00:00 EDT 2008,188335,38.609864,-121.492304 8952 ROCKY CREEK CT,ELK GROVE,95758,CA,3,2,1273,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.431239,-121.44001 435 EXCHANGE ST,SACRAMENTO,95838,CA,3,1,1082,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.659434,-121.455236 10105 MONTE VALLO CT,SACRAMENTO,95827,CA,4,2,1578,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.573917,-121.316916 3930 ANNABELLE AVE,ROSEVILLE,95661,CA,2,1,796,Residential,Fri May 16 00:00:00 EDT 2008,190000,38.727609,-121.226494 4854 TANGERINE AVE,SACRAMENTO,95823,CA,3,2,1386,Residential,Fri May 16 00:00:00 EDT 2008,191250,38.478239,-121.446326 2909 SHAWN WAY,RANCHO CORDOVA,95670,CA,3,2,1452,Residential,Fri May 16 00:00:00 EDT 2008,193000,38.589925,-121.299059 4290 BLACKFORD WAY,SACRAMENTO,95823,CA,3,2,1513,Residential,Fri May 16 00:00:00 EDT 2008,193500,38.470494,-121.454162 5890 TT TRAK,FORESTHILL,95631,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,194818,39.020808,-120.821518 7015 WOODSIDE DR,SACRAMENTO,95842,CA,4,2,1578,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.693071,-121.332365 6019 CHESHIRE WAY,CITRUS HEIGHTS,95610,CA,4,3,1736,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.676437,-121.279165 3330 VILLAGE CT,CAMERON PARK,95682,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.690504,-120.996245 2561 VERNA WAY,SACRAMENTO,95821,CA,3,1,1473,Residential,Fri May 16 00:00:00 EDT 2008,195000,38.611055,-121.369964 3522 22ND AVE,SACRAMENTO,95820,CA,3,1,1150,Residential,Fri May 16 00:00:00 EDT 2008,198000,38.532725,-121.469078 2880 CANDIDO DR,SACRAMENTO,95833,CA,3,2,1127,Residential,Fri May 16 00:00:00 EDT 2008,199900,38.618019,-121.510215 6908 PIN OAK CT,FAIR OAKS,95628,CA,3,1,1144,Residential,Fri May 16 00:00:00 EDT 2008,200000,38.66424,-121.303675 5733 ANGELINA AVE,CARMICHAEL,95608,CA,3,1,972,Residential,Fri May 16 00:00:00 EDT 2008,201000,38.622634,-121.330846 7849 BONNY DOWNS WAY,ELK GROVE,95758,CA,4,2,2306,Residential,Fri May 16 00:00:00 EDT 2008,204918,38.42139,-121.411339 8716 LONGSPUR WAY,ANTELOPE,95843,CA,3,2,1479,Residential,Fri May 16 00:00:00 EDT 2008,205000,38.724083,-121.3584 6320 EL DORADO ST,EL DORADO,95623,CA,2,1,1040,Residential,Fri May 16 00:00:00 EDT 2008,205000,38.678758,-120.844118 2328 DOROTHY JUNE WAY,SACRAMENTO,95838,CA,3,2,1430,Residential,Fri May 16 00:00:00 EDT 2008,205878,38.641727,-121.412703 1986 DANVERS WAY,SACRAMENTO,95832,CA,4,2,1800,Residential,Fri May 16 00:00:00 EDT 2008,207000,38.47723,-121.492568 7901 GAZELLE TRAIL WAY,ANTELOPE,95843,CA,4,2,1953,Residential,Fri May 16 00:00:00 EDT 2008,207744,38.71174,-121.342675 6080 BRIDGECROSS DR,SACRAMENTO,95835,CA,3,2,1120,Residential,Fri May 16 00:00:00 EDT 2008,209000,38.681952,-121.505009 20 GROTH CIR,SACRAMENTO,95834,CA,3,2,1232,Residential,Fri May 16 00:00:00 EDT 2008,210000,38.640807,-121.533522 1900 DANBROOK DR,SACRAMENTO,95835,CA,1,1,984,Condo,Fri May 16 00:00:00 EDT 2008,210944,38.668433,-121.503471 140 VENTO CT,ROSEVILLE,95678,CA,3,2,0,Condo,Fri May 16 00:00:00 EDT 2008,212500,38.793533,-121.289685 8442 KEUSMAN ST,ELK GROVE,95758,CA,4,2,2329,Residential,Fri May 16 00:00:00 EDT 2008,213750,38.449651,-121.414704 9552 SUNLIGHT LN,ELK GROVE,95758,CA,3,2,1351,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.410561,-121.404327 2733 YUMA CT,CAMERON PARK,95682,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.691215,-120.994949 1407 TIFFANY CIR,ROSEVILLE,95661,CA,4,1,1376,Residential,Fri May 16 00:00:00 EDT 2008,215000,38.736392,-121.2664 636 CRESTVIEW DR,DIAMOND SPRINGS,95619,CA,3,2,1300,Residential,Fri May 16 00:00:00 EDT 2008,216033,38.688255,-120.810235 1528 HESKET WAY,SACRAMENTO,95825,CA,4,2,1566,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.593598,-121.403637 2327 32ND ST,SACRAMENTO,95817,CA,2,1,1115,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.557433,-121.47034 1833 2ND AVE,SACRAMENTO,95818,CA,2,1,1032,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.556818,-121.490669 7252 CARRIAGE DR,CITRUS HEIGHTS,95621,CA,4,2,1419,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.698058,-121.294893 9815 PASO FINO WAY,ELK GROVE,95757,CA,3,2,1261,Residential,Fri May 16 00:00:00 EDT 2008,220000,38.404888,-121.443998 5532 ENGLE RD,CARMICHAEL,95608,CA,2,2,1637,Residential,Fri May 16 00:00:00 EDT 2008,220702,38.63173,-121.335286 1139 CLINTON RD,SACRAMENTO,95825,CA,4,2,1776,Multi-Family,Fri May 16 00:00:00 EDT 2008,221250,38.585291,-121.406824 9176 SAGE GLEN WAY,ELK GROVE,95758,CA,3,2,1338,Residential,Fri May 16 00:00:00 EDT 2008,222000,38.423913,-121.439115 9967 HATHERTON WAY,ELK GROVE,95757,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,222500,38.3052,-121.4033 9264 BOULDER RIVER WAY,ELK GROVE,95624,CA,5,2,2254,Residential,Fri May 16 00:00:00 EDT 2008,222750,38.421713,-121.345191 320 GROTH CIR,SACRAMENTO,95834,CA,3,2,1441,Residential,Fri May 16 00:00:00 EDT 2008,225000,38.638882,-121.531883 137 GUNNISON AVE,SACRAMENTO,95838,CA,4,2,1991,Residential,Fri May 16 00:00:00 EDT 2008,225000,38.650729,-121.466483 8209 RIVALLO WAY,SACRAMENTO,95829,CA,4,3,2126,Residential,Fri May 16 00:00:00 EDT 2008,228750,38.459524,-121.3501 8637 PERIWINKLE CIR,ELK GROVE,95624,CA,3,2,1094,Residential,Fri May 16 00:00:00 EDT 2008,229000,38.443184,-121.364388 3425 MEADOW WAY,ROCKLIN,95677,CA,3,2,1462,Residential,Fri May 16 00:00:00 EDT 2008,230095,38.798028,-121.235364 107 JARVIS CIR,SACRAMENTO,95834,CA,5,3,2258,Residential,Fri May 16 00:00:00 EDT 2008,232500,38.639891,-121.537603 2319 THORES ST,RANCHO CORDOVA,95670,CA,3,2,1074,Residential,Fri May 16 00:00:00 EDT 2008,233000,38.59675,-121.312716 8935 MOUNTAIN HOME CT,ELK GROVE,95624,CA,4,2,2111,Residential,Fri May 16 00:00:00 EDT 2008,233500,38.38751,-121.370276 2566 SERENATA WAY,SACRAMENTO,95835,CA,3,2,1686,Residential,Fri May 16 00:00:00 EDT 2008,239000,38.671556,-121.520916 4085 COUNTRY DR,ANTELOPE,95843,CA,4,3,1915,Residential,Fri May 16 00:00:00 EDT 2008,240000,38.706209,-121.369509 9297 TROUT WAY,ELK GROVE,95624,CA,4,2,2367,Residential,Fri May 16 00:00:00 EDT 2008,240000,38.420637,-121.375798 7 ARCHIBALD CT,SACRAMENTO,95823,CA,3,2,1962,Residential,Fri May 16 00:00:00 EDT 2008,240971,38.443305,-121.435296 11130 EEL RIVER CT,RANCHO CORDOVA,95670,CA,2,2,1406,Residential,Fri May 16 00:00:00 EDT 2008,242000,38.625932,-121.271517 8323 REDBANK WAY,SACRAMENTO,95829,CA,3,2,1789,Residential,Fri May 16 00:00:00 EDT 2008,243450,38.455753,-121.349273 16 BRONCO CREEK CT,SACRAMENTO,95835,CA,4,2,1876,Residential,Fri May 16 00:00:00 EDT 2008,243500,38.674226,-121.525497 8316 NORTHAM DR,ANTELOPE,95843,CA,3,2,1235,Residential,Fri May 16 00:00:00 EDT 2008,246544,38.720767,-121.376678 4240 WINJE DR,ANTELOPE,95843,CA,4,2,2504,Residential,Fri May 16 00:00:00 EDT 2008,246750,38.70884,-121.359559 3569 SODA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,247000,38.631139,-121.501879 5118 ROBANDER ST,CARMICHAEL,95608,CA,3,2,1676,Residential,Fri May 16 00:00:00 EDT 2008,247000,38.657267,-121.310352 5976 KYLENCH CT,CITRUS HEIGHTS,95621,CA,3,2,1367,Residential,Fri May 16 00:00:00 EDT 2008,249000,38.708966,-121.32467 9247 DELAIR WAY,ELK GROVE,95758,CA,4,3,1899,Residential,Fri May 16 00:00:00 EDT 2008,249000,38.422241,-121.458022 9054 DESCENDANT DR,ELK GROVE,95758,CA,3,2,1636,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.428852,-121.415628 3450 WHITNOR CT,SACRAMENTO,95821,CA,3,2,1828,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.627698,-121.369698 6288 LONETREE BLVD,ROCKLIN,95765,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,250000,38.804993,-121.293609 9355 MATADOR WAY,SACRAMENTO,95826,CA,4,2,1438,Residential,Fri May 16 00:00:00 EDT 2008,252000,38.555633,-121.350691 8671 SUMMER SUN WAY,ELK GROVE,95624,CA,3,2,1451,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.442845,-121.373272 1890 GENEVA PL,SACRAMENTO,95825,CA,3,1,1520,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.599449,-121.400305 1813 AVENIDA MARTINA,ROSEVILLE,95747,CA,3,2,1506,Residential,Fri May 16 00:00:00 EDT 2008,255000,38.776649,-121.339589 191 BARNHART CIR,SACRAMENTO,95835,CA,4,2,2605,Residential,Fri May 16 00:00:00 EDT 2008,257200,38.675594,-121.515878 6221 GREEN TOP WAY,ORANGEVALE,95662,CA,3,2,1196,Residential,Fri May 16 00:00:00 EDT 2008,260000,38.679409,-121.219107 2298 PRIMROSE LN,LINCOLN,95648,CA,3,2,1621,Residential,Fri May 16 00:00:00 EDT 2008,260000,38.89918,-121.322514 5635 LOS PUEBLOS WAY,SACRAMENTO,95835,CA,3,2,1811,Residential,Fri May 16 00:00:00 EDT 2008,263500,38.679191,-121.537622 10165 LOFTON WAY,ELK GROVE,95757,CA,3,2,1540,Residential,Fri May 16 00:00:00 EDT 2008,266510,38.387708,-121.436522 1251 GREEN RAVINE DR,LINCOLN,95648,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,267750,38.88156,-121.301343 6001 SHOO FLY RD,PLACERVILLE,95667,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,270000,38.813546,-120.809254 3040 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,271000,38.770835,-121.366996 2674 TAM O SHANTER DR,EL DORADO HILLS,95762,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,272700,38.695801,-121.079216 6007 MARYBELLE LN,SHINGLE SPRINGS,95682,CA,0,0,0,Unkown,Fri May 16 00:00:00 EDT 2008,275000,38.64347,-120.888183 9949 NESTLING CIR,ELK GROVE,95757,CA,3,2,1543,Residential,Fri May 16 00:00:00 EDT 2008,275000,38.397455,-121.468391 2915 HOLDREGE WAY,SACRAMENTO,95835,CA,5,3,2494,Residential,Fri May 16 00:00:00 EDT 2008,276000,38.663728,-121.525833 2678 BRIARTON DR,LINCOLN,95648,CA,3,2,1650,Residential,Fri May 16 00:00:00 EDT 2008,276500,38.844116,-121.274806 294 SPARROW DR,GALT,95632,CA,4,3,2214,Residential,Fri May 16 00:00:00 EDT 2008,278000,38.258976,-121.321266 2987 DIORITE WAY,SACRAMENTO,95835,CA,5,3,2280,Residential,Fri May 16 00:00:00 EDT 2008,279000,38.667332,-121.528276 6326 APPIAN WAY,CARMICHAEL,95608,CA,3,2,1443,Residential,Fri May 16 00:00:00 EDT 2008,280000,38.66266,-121.316858 6905 COBALT WAY,CITRUS HEIGHTS,95621,CA,4,2,1582,Residential,Fri May 16 00:00:00 EDT 2008,280000,38.691393,-121.305215 8986 HAFLINGER WAY,ELK GROVE,95757,CA,3,2,1857,Residential,Fri May 16 00:00:00 EDT 2008,285000,38.397923,-121.450219 2916 BABSON DR,ELK GROVE,95758,CA,3,2,1735,Residential,Fri May 16 00:00:00 EDT 2008,288000,38.417191,-121.473897 10133 NEBBIOLO CT,ELK GROVE,95624,CA,4,3,2096,Residential,Fri May 16 00:00:00 EDT 2008,289000,38.391085,-121.347231 1103 COMMONS DR,SACRAMENTO,95825,CA,3,2,1720,Residential,Fri May 16 00:00:00 EDT 2008,290000,38.567865,-121.410699 4636 TEAL BAY CT,ANTELOPE,95843,CA,4,2,2160,Residential,Fri May 16 00:00:00 EDT 2008,290000,38.704554,-121.354753 1524 YOUNGS AVE,SACRAMENTO,95838,CA,4,2,1382,Residential,Fri May 16 00:00:00 EDT 2008,293996,38.644927,-121.43054 865 CONRAD CT,PLACERVILLE,95667,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,294000,38.729993,-120.802458 8463 TERRACOTTA CT,ELK GROVE,95624,CA,4,2,1721,Residential,Fri May 16 00:00:00 EDT 2008,294173,38.450548,-121.363002 5747 KING RD,LOOMIS,95650,CA,4,2,1328,Residential,Fri May 16 00:00:00 EDT 2008,295000,38.825096,-121.198432 8253 KEEGAN WAY,ELK GROVE,95624,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,298000,38.446286,-121.400817 9204 TROUT WAY,ELK GROVE,95624,CA,4,2,1982,Residential,Fri May 16 00:00:00 EDT 2008,298000,38.422221,-121.375799 1828 2ND AVE,SACRAMENTO,95818,CA,2,1,1144,Residential,Fri May 16 00:00:00 EDT 2008,299000,38.556844,-121.490769 1113 COMMONS DR,SACRAMENTO,95825,CA,2,2,1623,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.567795,-121.410703 2341 BIG STRIKE TRL,COOL,95614,CA,3,2,1457,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.905927,-120.975169 9452 RED SPRUCE WAY,ELK GROVE,95624,CA,6,3,2555,Residential,Fri May 16 00:00:00 EDT 2008,300000,38.404505,-121.346938 5776 TERRACE DR,ROCKLIN,95765,CA,3,2,1577,Residential,Fri May 16 00:00:00 EDT 2008,300567,38.800539,-121.260979 5908 MCLEAN DR,ELK GROVE,95757,CA,5,3,2592,Residential,Fri May 16 00:00:00 EDT 2008,303000,38.38912,-121.434389 8215 PEREGRINE WAY,CITRUS HEIGHTS,95610,CA,3,2,1401,Residential,Fri May 16 00:00:00 EDT 2008,305000,38.715493,-121.26293 1104 HILLSDALE LN,LINCOLN,95648,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,306000,38.865017,-121.32302 2949 PANAMA AVE,CARMICHAEL,95608,CA,3,2,1502,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.618369,-121.326187 1356 HARTLEY WAY,FOLSOM,95630,CA,3,2,1327,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.651617,-121.131674 633 HANISCH DR,ROSEVILLE,95678,CA,4,3,1800,Residential,Fri May 16 00:00:00 EDT 2008,310000,38.76349,-121.275881 63 ANGEL ISLAND CIR,SACRAMENTO,95831,CA,4,2,2169,Residential,Fri May 16 00:00:00 EDT 2008,311518,38.490408,-121.547664 1571 WILD OAK LN,LINCOLN,95648,CA,5,3,2457,Residential,Fri May 16 00:00:00 EDT 2008,312000,38.844144,-121.274174 5222 COPPER SUNSET WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,313000,38.529181,-121.224755 5601 SPINDRIFT LN,ORANGEVALE,95662,CA,4,2,2004,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.668289,-121.192316 652 FIFTEEN MILE DR,ROSEVILLE,95678,CA,4,3,2212,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.775872,-121.298864 7921 DOE TRAIL WAY,ANTELOPE,95843,CA,5,3,3134,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.711927,-121.343608 4204 LUSK DR,SACRAMENTO,95864,CA,3,2,1360,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.606569,-121.368424 5321 DELTA DR,ROCKLIN,95765,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,315000,38.815493,-121.262908 5608 ROSEDALE WAY,SACRAMENTO,95822,CA,3,2,1276,Residential,Fri May 16 00:00:00 EDT 2008,320000,38.525115,-121.518689 3372 BERETANIA WAY,SACRAMENTO,95834,CA,4,3,2962,Residential,Fri May 16 00:00:00 EDT 2008,322000,38.64977,-121.53448 2422 STEFANIE DR,ROCKLIN,95765,CA,4,2,1888,Residential,Fri May 16 00:00:00 EDT 2008,325000,38.82273,-121.26424 3232 PARKHAM DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,325500,38.772821,-121.364821 448 ELMWOOD CT,ROSEVILLE,95678,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,326951,38.771917,-121.304439 1214 DAWNWOOD DR,GALT,95632,CA,3,2,1548,Residential,Fri May 16 00:00:00 EDT 2008,328370,38.290119,-121.286023 1440 EMERALD LN,LINCOLN,95648,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,330000,38.861864,-121.267478 3349 CORVINA DR,RANCHO CORDOVA,95670,CA,4,3,2109,Residential,Fri May 16 00:00:00 EDT 2008,330000,38.580545,-121.279016 10254 JULIANA WAY,SACRAMENTO,95827,CA,4,2,2484,Residential,Fri May 16 00:00:00 EDT 2008,331200,38.56803,-121.309966 149 OPUS CIR,SACRAMENTO,95834,CA,4,3,2258,Residential,Fri May 16 00:00:00 EDT 2008,332000,38.6354,-121.53499 580 REGENCY PARK CIR,SACRAMENTO,95835,CA,3,3,2212,Residential,Fri May 16 00:00:00 EDT 2008,334000,38.674864,-121.4958 5544 CAMAS CT,ORANGEVALE,95662,CA,3,2,1616,Residential,Fri May 16 00:00:00 EDT 2008,335000,38.667703,-121.209456 5102 ARCHCREST WAY,SACRAMENTO,95835,CA,4,2,2372,Residential,Fri May 16 00:00:00 EDT 2008,341000,38.66841,-121.494639 5725 BALFOR RD,ROCKLIN,95765,CA,5,3,2606,Residential,Fri May 16 00:00:00 EDT 2008,346375,38.807816,-121.270008 7697 ROSEHALL DR,ROSEVILLE,95678,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,347225,38.79218,-121.28595 4821 HUTSON WAY,ELK GROVE,95757,CA,5,3,2877,Residential,Fri May 16 00:00:00 EDT 2008,349000,38.386239,-121.448159 4509 WINJE DR,ANTELOPE,95843,CA,3,2,2960,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.709513,-121.359357 1965 LAURELHURST LN,LINCOLN,95648,CA,2,2,0,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.853869,-121.271742 6709 ROSE BRIDGE DR,ROSEVILLE,95678,CA,3,2,2172,Residential,Fri May 16 00:00:00 EDT 2008,350000,38.792461,-121.275711 281 SPYGLASS HL,ROSEVILLE,95678,CA,3,2,2100,Condo,Fri May 16 00:00:00 EDT 2008,350000,38.762153,-121.283451 7709 RIVER VILLAGE DR,SACRAMENTO,95831,CA,3,2,1795,Residential,Fri May 16 00:00:00 EDT 2008,351000,38.483212,-121.54019 4165 BRISBANE CIR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,356200,38.686067,-121.073413 506 BEDFORD CT,ROSEVILLE,95661,CA,4,2,2295,Residential,Fri May 16 00:00:00 EDT 2008,360000,38.733985,-121.236766 9048 PINTO CANYON WAY,ROSEVILLE,95747,CA,4,3,2577,Residential,Fri May 16 00:00:00 EDT 2008,367463,38.792493,-121.331899 2274 IVY BRIDGE DR,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,375000,38.778561,-121.362008 14004 WALNUT AVE,WALNUT GROVE,95690,CA,3,1,1727,Residential,Fri May 16 00:00:00 EDT 2008,380000,38.247659,-121.515129 6905 FRANKFORT CT,ELK GROVE,95758,CA,3,2,1485,Residential,Fri May 16 00:00:00 EDT 2008,380578,38.429139,-121.423444 3621 WINTUN DR,CARMICHAEL,95608,CA,3,2,1655,Residential,Fri May 16 00:00:00 EDT 2008,386222,38.629929,-121.323086 201 KIRKLAND CT,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,389000,38.867125,-121.319085 12075 APPLESBURY CT,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,390000,38.5357,-121.2249 1975 SIDESADDLE WAY,ROSEVILLE,95661,CA,3,2,2049,Residential,Fri May 16 00:00:00 EDT 2008,395500,38.737872,-121.249025 5420 ALMOND FALLS WAY,RANCHO CORDOVA,95742,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,396000,38.527384,-121.233531 9677 PILLITERI CT,ELK GROVE,95757,CA,5,3,2875,Residential,Fri May 16 00:00:00 EDT 2008,397000,38.405571,-121.445186 1515 EL CAMINO VERDE DR,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,400000,38.904869,-121.32075 556 PLATT CIR,EL DORADO HILLS,95762,CA,4,2,2199,Residential,Fri May 16 00:00:00 EDT 2008,400000,38.656299,-121.079783 1792 DIAMOND WOODS CIR,ROSEVILLE,95747,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,412500,38.808581,-121.32785 1124 PERKINS WAY,SACRAMENTO,95818,CA,2,1,1304,Residential,Fri May 16 00:00:00 EDT 2008,413500,38.551611,-121.504437 4748 SALEM WAY,CARMICHAEL,95608,CA,3,2,2334,Residential,Fri May 16 00:00:00 EDT 2008,415000,38.634111,-121.353376 1484 RADCLIFFE WAY,AUBURN,95603,CA,4,3,2278,Residential,Fri May 16 00:00:00 EDT 2008,420454,38.935579,-121.079018 51 AIKEN WAY,SACRAMENTO,95819,CA,3,1,1493,Residential,Fri May 16 00:00:00 EDT 2008,425000,38.579326,-121.44252 2818 KNOLLWOOD DR,CAMERON PARK,95682,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,425000,38.669805,-120.999007 1536 STONEY CROSS LN,LINCOLN,95648,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,433500,38.860007,-121.310946 509 CASTILLIAN CT,ROSEVILLE,95747,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,438000,38.804773,-121.341195 700 HUNTER PL,FOLSOM,95630,CA,5,3,2787,Residential,Fri May 16 00:00:00 EDT 2008,441000,38.66051,-121.163689 1240 FAY CIR,SACRAMENTO,95831,CA,5,3,2824,Residential,Fri May 16 00:00:00 EDT 2008,445000,38.506371,-121.514456 1113 SANDWICK WAY,FOLSOM,95630,CA,4,3,3261,Residential,Fri May 16 00:00:00 EDT 2008,446000,38.673882,-121.105077 3108 DELWOOD WAY,SACRAMENTO,95821,CA,4,2,2053,Residential,Fri May 16 00:00:00 EDT 2008,450000,38.621566,-121.370882 3212 CORNICHE LN,ROSEVILLE,95661,CA,4,3,2379,Residential,Fri May 16 00:00:00 EDT 2008,455000,38.750577,-121.232768 2159 BECKETT DR,EL DORADO HILLS,95762,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,460000,38.680092,-121.036467 4320 FOUR SEASONS RD,PLACERVILLE,95667,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,475000,38.690867,-120.693641 6401 MARSHALL RD,GARDEN VALLEY,95633,CA,3,2,0,Residential,Fri May 16 00:00:00 EDT 2008,490000,38.84255,-120.8754 2089 BECKETT DR,EL DORADO HILLS,95762,CA,4,2,0,Residential,Fri May 16 00:00:00 EDT 2008,493000,38.681778,-121.035838 6196 EDGEHILL DR,EL DORADO HILLS,95762,CA,5,4,0,Residential,Fri May 16 00:00:00 EDT 2008,508000,38.676131,-121.038931 200 HILLSFORD CT,ROSEVILLE,95747,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,511000,38.780051,-121.378718 8217 PLUMERIA AVE,FAIR OAKS,95628,CA,3,2,3173,Residential,Fri May 16 00:00:00 EDT 2008,525000,38.650735,-121.258628 4841 VILLAGE GREEN DR,EL DORADO HILLS,95762,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,533000,38.664066,-121.056735 3863 LAS PASAS WAY,SACRAMENTO,95864,CA,3,1,1348,Residential,Fri May 16 00:00:00 EDT 2008,545000,38.588936,-121.373606 820 DANA CT,AUBURN,95603,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,560000,38.865246,-121.094869 1165 37TH ST,SACRAMENTO,95816,CA,2,1,1252,Residential,Fri May 16 00:00:00 EDT 2008,575000,38.568438,-121.457854 203 CASCADE FALLS DR,FOLSOM,95630,CA,4,3,3229,Residential,Fri May 16 00:00:00 EDT 2008,575000,38.703962,-121.1871 9880 IZILDA CT,SACRAMENTO,95829,CA,5,4,3863,Residential,Fri May 16 00:00:00 EDT 2008,598695,38.45326,-121.32573 1800 AVONDALE DR,ROSEVILLE,95747,CA,5,3,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.798448,-121.344054 4620 BROMWICH CT,ROCKLIN,95677,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.772672,-121.220232 620 KESWICK CT,GRANITE BAY,95746,CA,4,3,2356,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.732096,-121.219142 4478 GREENBRAE RD,ROCKLIN,95677,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,600000,38.781134,-121.222801 8432 BRIGGS DR,ROSEVILLE,95747,CA,5,3,3579,Residential,Fri May 16 00:00:00 EDT 2008,610000,38.78861,-121.339495 200 CRADLE MOUNTAIN CT,EL DORADO HILLS,95762,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,622500,38.6478,-121.0309 2065 IMPRESSIONIST WAY,EL DORADO HILLS,95762,CA,0,0,0,Residential,Fri May 16 00:00:00 EDT 2008,680000,38.682961,-121.033253 2982 ABERDEEN LN,EL DORADO HILLS,95762,CA,4,3,0,Residential,Fri May 16 00:00:00 EDT 2008,879000,38.706692,-121.058869 9401 BARREL RACER CT,WILTON,95693,CA,4,3,4400,Residential,Fri May 16 00:00:00 EDT 2008,884790,38.415298,-121.194858 3720 VISTA DE MADERA,LINCOLN,95648,CA,3,3,0,Residential,Fri May 16 00:00:00 EDT 2008,1551,38.851645,-121.231742 14151 INDIO DR,SLOUGHHOUSE,95683,CA,3,4,5822,Residential,Fri May 16 00:00:00 EDT 2008,2000,38.490447,-121.129337 7401 TOULON LN,SACRAMENTO,95828,CA,4,2,1512,Residential,Thu May 15 00:00:00 EDT 2008,56950,38.488628,-121.387759 9127 NEWHALL DR Unit 34,SACRAMENTO,95826,CA,1,1,611,Condo,Thu May 15 00:00:00 EDT 2008,60000,38.542419,-121.359904 5937 BAMFORD DR,SACRAMENTO,95823,CA,2,1,876,Residential,Thu May 15 00:00:00 EDT 2008,61000,38.471139,-121.432255 5672 HILLSDALE BLVD,SACRAMENTO,95842,CA,2,1,933,Condo,Thu May 15 00:00:00 EDT 2008,62000,38.670467,-121.359799 3920 39TH ST,SACRAMENTO,95820,CA,2,1,864,Residential,Thu May 15 00:00:00 EDT 2008,68566,38.539213,-121.46393 701 JESSIE AVE,SACRAMENTO,95838,CA,2,1,1011,Residential,Thu May 15 00:00:00 EDT 2008,70000,38.643978,-121.449562 83 ARCADE BLVD,SACRAMENTO,95815,CA,4,2,1158,Residential,Thu May 15 00:00:00 EDT 2008,80000,38.618716,-121.466327 601 REGGINALD WAY,SACRAMENTO,95838,CA,3,2,1092,Residential,Thu May 15 00:00:00 EDT 2008,85500,38.64472,-121.452228 550 DEL VERDE CIR,SACRAMENTO,95833,CA,2,1,956,Condo,Thu May 15 00:00:00 EDT 2008,92000,38.627147,-121.500799 4113 DAYSTAR CT,SACRAMENTO,95824,CA,2,2,1139,Residential,Thu May 15 00:00:00 EDT 2008,93600,38.520469,-121.458606 7374 TISDALE WAY,SACRAMENTO,95822,CA,3,1,1058,Residential,Thu May 15 00:00:00 EDT 2008,95000,38.488238,-121.472561 3348 RIO LINDA BLVD,SACRAMENTO,95838,CA,3,2,1040,Residential,Thu May 15 00:00:00 EDT 2008,97750,38.628842,-121.446127 3935 LIMESTONE WAY,SACRAMENTO,95823,CA,3,2,1354,Residential,Thu May 15 00:00:00 EDT 2008,104000,38.484374,-121.463157 6208 GRATTAN WAY,NORTH HIGHLANDS,95660,CA,3,1,1051,Residential,Thu May 15 00:00:00 EDT 2008,105000,38.679279,-121.376615 739 E WOODSIDE LN Unit E,SACRAMENTO,95825,CA,1,1,682,Condo,Thu May 15 00:00:00 EDT 2008,107666,38.578675,-121.409951 4225 46TH AVE,SACRAMENTO,95824,CA,3,1,1161,Residential,Thu May 15 00:00:00 EDT 2008,109000,38.511893,-121.457676 1434 BELL AVE,SACRAMENTO,95838,CA,3,1,1004,Residential,Thu May 15 00:00:00 EDT 2008,110000,38.647398,-121.432914 5628 GEORGIA DR,NORTH HIGHLANDS,95660,CA,3,1,1229,Residential,Thu May 15 00:00:00 EDT 2008,110000,38.669587,-121.379879 7629 BETH ST,SACRAMENTO,95832,CA,3,2,1249,Residential,Thu May 15 00:00:00 EDT 2008,112500,38.480126,-121.487869 2277 BABETTE WAY,SACRAMENTO,95832,CA,3,2,1161,Residential,Thu May 15 00:00:00 EDT 2008,114800,38.479593,-121.48434 6561 WEATHERFORD WAY,SACRAMENTO,95823,CA,3,1,1010,Residential,Thu May 15 00:00:00 EDT 2008,116000,38.465551,-121.42661 3035 ESTEPA DR Unit 5C,CAMERON PARK,95682,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,119000,38.681393,-120.996713 5136 CABOT CIR,SACRAMENTO,95820,CA,4,2,1462,Residential,Thu May 15 00:00:00 EDT 2008,121500,38.528479,-121.411806 7730 ROBINETTE RD,SACRAMENTO,95828,CA,3,2,1269,Residential,Thu May 15 00:00:00 EDT 2008,122000,38.47709,-121.410569 87 LACAM CIR,SACRAMENTO,95820,CA,2,2,1188,Residential,Thu May 15 00:00:00 EDT 2008,123675,38.532359,-121.41167 1691 NOGALES ST,SACRAMENTO,95838,CA,4,2,1570,Residential,Thu May 15 00:00:00 EDT 2008,126854,38.631925,-121.427775 3118 42ND ST,SACRAMENTO,95817,CA,3,2,1093,Residential,Thu May 15 00:00:00 EDT 2008,127059,38.546091,-121.457745 7517 50TH AVE,SACRAMENTO,95828,CA,3,1,962,Residential,Thu May 15 00:00:00 EDT 2008,128687,38.507339,-121.416267 4071 EVALITA WAY,SACRAMENTO,95823,CA,3,2,1089,Residential,Thu May 15 00:00:00 EDT 2008,129500,38.466388,-121.458861 7928 36TH AVE,SACRAMENTO,95824,CA,3,2,1127,Residential,Thu May 15 00:00:00 EDT 2008,130000,38.52049,-121.411383 6631 DEMARET DR,SACRAMENTO,95822,CA,4,2,1309,Residential,Thu May 15 00:00:00 EDT 2008,131750,38.506382,-121.483574 7043 9TH AVE,RIO LINDA,95673,CA,2,1,970,Residential,Thu May 15 00:00:00 EDT 2008,132000,38.695589,-121.444133 97 KENNELFORD CIR,SACRAMENTO,95823,CA,3,2,1144,Residential,Thu May 15 00:00:00 EDT 2008,134000,38.462376,-121.426556 2636 TRONERO WAY,RANCHO CORDOVA,95670,CA,3,1,1000,Residential,Thu May 15 00:00:00 EDT 2008,134000,38.593049,-121.30304 1530 TOPANGA LN Unit 204,LINCOLN,95648,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,138000,38.88415,-121.270277 3604 KODIAK WAY,ANTELOPE,95843,CA,3,2,1206,Residential,Thu May 15 00:00:00 EDT 2008,142000,38.706175,-121.379776 2149 COTTAGE WAY,SACRAMENTO,95825,CA,3,1,1285,Residential,Thu May 15 00:00:00 EDT 2008,143012,38.603593,-121.417011 8632 PRAIRIEWOODS DR,SACRAMENTO,95828,CA,3,2,1543,Residential,Thu May 15 00:00:00 EDT 2008,145846,38.477563,-121.384382 612 STONE BLVD,WEST SACRAMENTO,95691,CA,2,1,884,Residential,Thu May 15 00:00:00 EDT 2008,147000,38.563084,-121.535579 4180 12TH AVE,SACRAMENTO,95817,CA,3,1,1019,Residential,Thu May 15 00:00:00 EDT 2008,148750,38.54117,-121.458129 8025 ARROYO VISTA DR,SACRAMENTO,95823,CA,4,2,1392,Residential,Thu May 15 00:00:00 EDT 2008,150000,38.46654,-121.419029 5754 WALERGA RD Unit 4,SACRAMENTO,95842,CA,2,1,924,Condo,Thu May 15 00:00:00 EDT 2008,150454,38.672567,-121.356754 8 LA ROCAS CT,SACRAMENTO,95823,CA,3,2,1217,Residential,Thu May 15 00:00:00 EDT 2008,151087,38.46616,-121.448283 8636 LONGSPUR WAY,ANTELOPE,95843,CA,3,2,1670,Residential,Thu May 15 00:00:00 EDT 2008,157296,38.725873,-121.35856 1941 EXPEDITION WAY,SACRAMENTO,95832,CA,3,2,1302,Residential,Thu May 15 00:00:00 EDT 2008,157500,38.473775,-121.493777 4351 TURNBRIDGE DR,SACRAMENTO,95823,CA,3,2,1488,Residential,Thu May 15 00:00:00 EDT 2008,160000,38.502034,-121.456027 6513 HOLIDAY WAY,NORTH HIGHLANDS,95660,CA,3,2,1373,Residential,Thu May 15 00:00:00 EDT 2008,160000,38.685361,-121.376938 8321 MISTLETOE WAY,CITRUS HEIGHTS,95621,CA,4,2,1381,Residential,Thu May 15 00:00:00 EDT 2008,161250,38.717738,-121.308322 5920 VALLEY GLEN WAY,SACRAMENTO,95823,CA,3,2,1265,Residential,Thu May 15 00:00:00 EDT 2008,164000,38.462821,-121.433135 2601 SAN FERNANDO WAY,SACRAMENTO,95818,CA,2,1,881,Residential,Thu May 15 00:00:00 EDT 2008,165000,38.556178,-121.476256 501 POPLAR AVE,WEST SACRAMENTO,95691,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,165000,38.584526,-121.534609 8008 SAINT HELENA CT,SACRAMENTO,95829,CA,4,2,1608,Residential,Thu May 15 00:00:00 EDT 2008,165750,38.467012,-121.359969 6517 DONEGAL DR,CITRUS HEIGHTS,95621,CA,3,1,1344,Residential,Thu May 15 00:00:00 EDT 2008,166000,38.681554,-121.312934 1001 RIO NORTE WAY,SACRAMENTO,95834,CA,3,2,1202,Residential,Thu May 15 00:00:00 EDT 2008,169000,38.634292,-121.485106 604 P ST,LINCOLN,95648,CA,3,2,1104,Residential,Thu May 15 00:00:00 EDT 2008,170000,38.893168,-121.305398 10001 WOODCREEK OAKS BLVD Unit 815,ROSEVILLE,95747,CA,2,2,0,Condo,Thu May 15 00:00:00 EDT 2008,170000,38.795529,-121.328819 7351 GIGI PL,SACRAMENTO,95828,CA,4,2,1859,Multi-Family,Thu May 15 00:00:00 EDT 2008,170000,38.490606,-121.410173 7740 DIXIE LOU ST,SACRAMENTO,95832,CA,3,2,1232,Residential,Thu May 15 00:00:00 EDT 2008,170000,38.475853,-121.477039 7342 DAVE ST,SACRAMENTO,95828,CA,3,1,1638,Residential,Thu May 15 00:00:00 EDT 2008,170725,38.490822,-121.401643 7687 HOWERTON DR,SACRAMENTO,95831,CA,2,2,1177,Residential,Thu May 15 00:00:00 EDT 2008,171750,38.480859,-121.539745 26 KAMSON CT,SACRAMENTO,95833,CA,3,2,1582,Residential,Thu May 15 00:00:00 EDT 2008,172000,38.622794,-121.499173 7045 PEEVEY CT,SACRAMENTO,95823,CA,2,2,904,Residential,Thu May 15 00:00:00 EDT 2008,173056,38.502254,-121.451444 8916 GABLES MILL PL,ELK GROVE,95758,CA,3,2,1340,Residential,Thu May 15 00:00:00 EDT 2008,174000,38.433919,-121.422347 1140 EDMONTON DR,SACRAMENTO,95833,CA,3,2,1204,Residential,Thu May 15 00:00:00 EDT 2008,174250,38.62457,-121.486913 8879 APPLE PEAR CT,ELK GROVE,95624,CA,4,2,1477,Residential,Thu May 15 00:00:00 EDT 2008,176850,38.44574,-121.3725 9 WIND CT,SACRAMENTO,95823,CA,4,2,1497,Residential,Thu May 15 00:00:00 EDT 2008,179500,38.45073,-121.427528 8570 SHERATON DR,FAIR OAKS,95628,CA,3,1,960,Residential,Thu May 15 00:00:00 EDT 2008,185000,38.667254,-121.240708 1550 TOPANGA LN Unit 207,LINCOLN,95648,CA,0,0,0,Condo,Thu May 15 00:00:00 EDT 2008,188000,38.88417,-121.270222 1080 RIO NORTE WAY,SACRAMENTO,95834,CA,3,2,1428,Residential,Thu May 15 00:00:00 EDT 2008,188700,38.634335,-121.486098 5501 VALLETTA WAY,SACRAMENTO,95820,CA,3,1,1039,Residential,Thu May 15 00:00:00 EDT 2008,189000,38.530144,-121.43749 5624 MEMORY LN,FAIR OAKS,95628,CA,3,1,1529,Residential,Thu May 15 00:00:00 EDT 2008,189000,38.66745,-121.2364 6622 WILLOWLEAF DR,CITRUS HEIGHTS,95621,CA,4,3,1892,Residential,Thu May 15 00:00:00 EDT 2008,189836,38.699714,-121.311635 27 MEGAN CT,SACRAMENTO,95838,CA,4,2,1887,Residential,Thu May 15 00:00:00 EDT 2008,190000,38.649258,-121.465308 6601 WOODMORE OAKS DR,ORANGEVALE,95662,CA,3,2,1294,Residential,Thu May 15 00:00:00 EDT 2008,191250,38.687006,-121.254319 1973 DANVERS WAY,SACRAMENTO,95832,CA,3,2,1638,Residential,Thu May 15 00:00:00 EDT 2008,191675,38.477568,-121.492574 8001 ARROYO VISTA DR,SACRAMENTO,95823,CA,3,2,1677,Residential,Thu May 15 00:00:00 EDT 2008,195500,38.46734,-121.419843 7409 VOYAGER WAY,CITRUS HEIGHTS,95621,CA,3,1,1073,Residential,Thu May 15 00:00:00 EDT 2008,198000,38.700717,-121.3133 815 CROSSWIND DR,SACRAMENTO,95838,CA,3,2,1231,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.651386,-121.45042 5509 LAGUNA CREST WAY,ELK GROVE,95758,CA,3,2,1175,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.42442,-121.440357 8424 MERRY HILL WAY,ELK GROVE,95624,CA,3,2,1416,Residential,Thu May 15 00:00:00 EDT 2008,200000,38.452075,-121.366461 1525 PENNSYLVANIA AVE,WEST SACRAMENTO,95691,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,200100,38.569943,-121.527539 5954 BRIDGECROSS DR,SACRAMENTO,95835,CA,3,2,1358,Residential,Thu May 15 00:00:00 EDT 2008,201528,38.68197,-121.500025 8789 SEQUOIA WOOD CT,ELK GROVE,95624,CA,4,2,1609,Residential,Thu May 15 00:00:00 EDT 2008,204750,38.438818,-121.37443 6600 SILVERTHORNE CIR,SACRAMENTO,95842,CA,4,3,1968,Residential,Thu May 15 00:00:00 EDT 2008,205000,38.68607,-121.342369 2221 2ND AVE,SACRAMENTO,95818,CA,2,2,1089,Residential,Thu May 15 00:00:00 EDT 2008,205000,38.555781,-121.485331 3230 SMATHERS WAY,CARMICHAEL,95608,CA,3,2,1296,Residential,Thu May 15 00:00:00 EDT 2008,205900,38.623372,-121.347665 5209 LAGUNA CREST WAY,ELK GROVE,95758,CA,2,2,1189,Residential,Thu May 15 00:00:00 EDT 2008,207000,38.424421,-121.443915 416 LEITCH AVE,SACRAMENTO,95815,CA,2,1,795,Residential,Thu May 15 00:00:00 EDT 2008,207973,38.612694,-121.456669 2100 BEATTY WAY,ROSEVILLE,95747,CA,3,2,1371,Residential,Thu May 15 00:00:00 EDT 2008,208250,38.737882,-121.308142 6920 GILLINGHAM WAY,NORTH HIGHLANDS,95660,CA,3,1,1310,Residential,Thu May 15 00:00:00 EDT 2008,208318,38.694279,-121.373395 82 WILDFLOWER DR,GALT,95632,CA,3,2,1262,Residential,Thu May 15 00:00:00 EDT 2008,209347,38.259708,-121.311616 8652 BANTON CIR,ELK GROVE,95624,CA,4,2,1740,Residential,Thu May 15 00:00:00 EDT 2008,211500,38.444,-121.370993 8428 MISTY PASS WAY,ANTELOPE,95843,CA,3,2,1517,Residential,Thu May 15 00:00:00 EDT 2008,212000,38.722959,-121.347115 7958 ROSEVIEW WAY,SACRAMENTO,95828,CA,3,2,1450,Residential,Thu May 15 00:00:00 EDT 2008,213000,38.467836,-121.410366 9020 LUKEN CT,ELK GROVE,95624,CA,3,2,1416,Residential,Thu May 15 00:00:00 EDT 2008,216000,38.451398,-121.366614 7809 VALLECITOS WAY,SACRAMENTO,95828,CA,3,1,888,Residential,Thu May 15 00:00:00 EDT 2008,216021,38.508217,-121.411207 8445 OLD AUBURN RD,CITRUS HEIGHTS,95610,CA,3,2,1882,Residential,Thu May 15 00:00:00 EDT 2008,219000,38.715423,-121.246743 10085 ATKINS DR,ELK GROVE,95757,CA,3,2,1302,Residential,Thu May 15 00:00:00 EDT 2008,219794,38.390893,-121.437821 9185 CERROLINDA CIR,ELK GROVE,95758,CA,3,2,1418,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.424497,-121.426595 9197 CORTINA CIR,ROSEVILLE,95678,CA,3,2,0,Condo,Thu May 15 00:00:00 EDT 2008,220000,38.793152,-121.290025 5429 HESPER WAY,CARMICHAEL,95608,CA,4,2,1319,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.665104,-121.315901 1178 WARMWOOD CT,GALT,95632,CA,4,2,1770,Residential,Thu May 15 00:00:00 EDT 2008,220000,38.289544,-121.284607 4900 ELUDE CT,SACRAMENTO,95842,CA,4,2,1627,Residential,Thu May 15 00:00:00 EDT 2008,223000,38.69674,-121.350519 3557 SODA WAY,SACRAMENTO,95834,CA,0,0,0,Residential,Thu May 15 00:00:00 EDT 2008,224000,38.631026,-121.501879 3528 SAINT GEORGE DR,SACRAMENTO,95821,CA,3,1,1040,Residential,Thu May 15 00:00:00 EDT 2008,224000,38.629468,-121.376445 7381 WASHBURN WAY,NORTH HIGHLANDS,95660,CA,3,1,960,Residential,Thu May 15 00:00:00 EDT 2008,224252,38.70355,-121.375103 2181 WINTERHAVEN CIR,CAMERON PARK,95682,CA,3,2,0,Residential,Thu May 15 00:00:00 EDT 2008,224500,38.69757,-120.995739 7540 HICKORY AVE,ORANGEVALE,95662,CA,3,1,1456,Residential,Thu May 15 00:00:00 EDT 2008,225000,38.703056,-121.235221 5024 CHAMBERLIN CIR,ELK GROVE,95757,CA,3,2,1450,Residential,Thu May 15 00:00:00 EDT 2008,228000,38.389756,-121.446246 2400 INVERNESS DR,LINCOLN,95648,CA,3,2,1358,Residential,Thu May 15 00:00:00 EDT 2008,229027,38.897814,-121.324691 5 BISHOPGATE CT,SACRAMENTO,95823,CA,4,2,1329,Residential,Thu May 15 00:00:00 EDT 2008,229500,38.467936,-121.445477 5601 REXLEIGH DR,SACRAMENTO,95823,CA,4,2,1715,Residential,Thu May 15 00:00:00 EDT 2008,230000,38.445342,-121.441504 1909 YARNELL WAY,ELK GROVE,95758,CA,3,2,1262,Residential,Thu May 15 00:00:00 EDT 2008,230000,38.417382,-121.484325 9169 GARLINGTON CT,SACRAMENTO,95829,CA,4,3,2280,Residential,Thu May 15 00:00:00 EDT 2008,232425,38.457679,-121.35962 6932 RUSKUT WAY,SACRAMENTO,95823,CA,3,2,1477,Residential,Thu May 15 00:00:00 EDT 2008,234000,38.499893,-121.45889 7933 DAFFODIL WAY,CITRUS HEIGHTS,95610,CA,3,2,1216,Residential,Thu May 15 00:00:00 EDT 2008,235000,38.708824,-121.256803 8304 RED FOX WAY,ELK GROVE,95758,CA,4,2,1685,Residential,Thu May 15 00:00:00 EDT 2008,235301,38.417,-121.397424 3882 YELLOWSTONE LN,EL DORADO HILLS,95762,CA,3,2,1362,Residential,Thu May 15 00:00:00 EDT 2008,235738,38.655245,-121.075915 \ No newline at end of file diff --git a/training/demos/08-text-files/pandas-demo/source/xls_read_demo.py b/training/demos/08-text-files/pandas-demo/source/xls_read_demo.py new file mode 100644 index 0000000..c3421a7 --- /dev/null +++ b/training/demos/08-text-files/pandas-demo/source/xls_read_demo.py @@ -0,0 +1,26 @@ +""" +Pandas getting started script. + +Pandas introduction demo script for Python beginners. +Makes a few calls taken from the official docs to see what can be done +with Pandas. + +See Also: +https://pandas.pydata.org/docs/getting_started/comparison/comparison_with_sql.html + +""" +import pandas as pd + +if __name__ == "__main__": + # Read dataframe from CSV file + frame: pd.DataFrame = pd.read_excel("files/demo-file-1000.xls") + # Get basic information on data + print(frame.dtypes) + + # Access, within column zero, to all rows + for row in frame["First Name"]: + print(row) + + # Make the equivalent to a SELECT WHERE query + # Get a frame where the age column is >= 40 + print(frame[frame["Age"] >= 40]) diff --git a/training/demos/09-sqlite/orm-peewee/README.md b/training/demos/09-sqlite/orm-peewee/README.md new file mode 100644 index 0000000..d594cc2 --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/README.md @@ -0,0 +1,4 @@ +# Simple ORM demo with Peewee + +Peewee simple definition of a model and simple code to +take advantage of the tool. diff --git a/training/demos/09-sqlite/orm-peewee/requirements.txt b/training/demos/09-sqlite/orm-peewee/requirements.txt new file mode 100644 index 0000000..52b81ee --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/requirements.txt @@ -0,0 +1 @@ +peewee diff --git a/training/demos/09-sqlite/orm-peewee/source/database/demo-file.sqlite3 b/training/demos/09-sqlite/orm-peewee/source/database/demo-file.sqlite3 new file mode 100644 index 0000000..a7c129d Binary files /dev/null and b/training/demos/09-sqlite/orm-peewee/source/database/demo-file.sqlite3 differ diff --git a/training/demos/09-sqlite/orm-peewee/source/demo_app.py b/training/demos/09-sqlite/orm-peewee/source/demo_app.py new file mode 100644 index 0000000..182152b --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/source/demo_app.py @@ -0,0 +1,27 @@ +""" +Simple demo application to showcase Peewee. + +Simple script with model definition to showcase the +use of ORMs and Peewee for beginners in database usage. + +""" +import peewee as pw # pip install peewee +from models import Person + + +if __name__ == "__main__": # Only True if current script is executed manually. + # Initialize a Peewee database for SQLite + db = pw.SqliteDatabase("database/demo-file.sqlite3") + # Make the Person model use the database. + Person.bind(db) + # Query the `person` table. + query = Person.select().where(Person.age > 50) + + # Display the results with a friendly formatting. + print(f"List of people older than 50 years old:\n{'–' * 80}") + for person in query: # type: Person + print(f"{person.id:02d}. {person.get_full_name():<30}: {person.age} years old.") + + # Exemple pour créer un nouvel objet Person dans ma table + # nouvelle_personne = Person(first_name="Bob", last_name="Bob", age=90) + # nouvelle_personne.save() diff --git a/training/demos/09-sqlite/orm-peewee/source/demo_test.py b/training/demos/09-sqlite/orm-peewee/source/demo_test.py new file mode 100644 index 0000000..f154277 --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/source/demo_test.py @@ -0,0 +1 @@ +import demo_app diff --git a/training/demos/09-sqlite/orm-peewee/source/models/__init__.py b/training/demos/09-sqlite/orm-peewee/source/models/__init__.py new file mode 100644 index 0000000..3ed5f88 --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/source/models/__init__.py @@ -0,0 +1,3 @@ +from .person import Person + +__all__ = ["Person"] diff --git a/training/demos/09-sqlite/orm-peewee/source/models/person.py b/training/demos/09-sqlite/orm-peewee/source/models/person.py new file mode 100644 index 0000000..afd431b --- /dev/null +++ b/training/demos/09-sqlite/orm-peewee/source/models/person.py @@ -0,0 +1,32 @@ +import peewee as pw + + +class Person(pw.Model): + """ + Model class for the Person table. + + Simple representation as a class of the Person + table columns. Each object of a Person can be persisted or + retrieved from the database. + + Attributes: + Person.id: identifier column. Primary key. + Person.last_name: N/A + Person.first_name: N/A + Person.age: Age of the person in years. + + """ + id = pw.BigAutoField(primary_key=True) + last_name = pw.CharField(column_name="nom", max_length=30, null=False) + first_name = pw.CharField(column_name="prenom", max_length=20, null=False) + age = pw.IntegerField(null=False) + + class Meta: + indexes = ( + # Make a UNIQUE index with the two following columns + (("last_name", "first_name"), True), + ) + + def get_full_name(self) -> str: + """Get the full name of the person.""" + return f"{self.first_name} {self.last_name}" diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/application.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/application.html new file mode 100644 index 0000000..62dc812 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/application.html @@ -0,0 +1,102 @@ + + + + + + +data-conversion.application API documentation + + + + + + + + + + + +
+
+
+

Module data-conversion.application

+
+
+

Entry point for our demo application.

+

Uses a "WindowManager" class holding the main window and the +CSV data manager used in it.

+

Configuring your project for the application

+

You will need to associate the code to a project if not +already done. If you don't have a project, just opening the folder +with PyCharm should suffice.

+

However, you need to have a virtualenv for your project (for good +practice), that uses Python 3.6+.

+

In this virtualenv, you'll have to install :

+
    +
  • pyside6
  • +
+

Note that Qt has issues with theming; if PySide6 is installed, using pip or +another medium, it won't follow the system theme. However, if PySide2 is +installed globally on the system (via apt-get or pacman), programs seem to +follow the system theme. One would then have to revert to importing from +PySide2 instead of PySide6 (with no other changes).

+

How to run the application

+

The application is very simple to run in PyCharm. +To do it, right-click on the source file content pane, somewhere where +there is an empty space.

+

Then, click the Run <application>....

+
+ +Expand source code + +
"""
+Entry point for our demo application.
+
+Uses a "WindowManager" class holding the main window and the
+CSV data manager used in it.
+
+.. include:: documentation/includes/application.md
+
+"""
+from PySide6.QtWidgets import QApplication
+
+from interface import WindowManager  # look at interface/__init__.py
+
+if __name__ == "__main__":
+    application = QApplication()
+    window_manager = WindowManager()
+    window_manager.show()
+    application.exec()
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/index.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/index.html new file mode 100644 index 0000000..31f4607 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/index.html @@ -0,0 +1,70 @@ + + + + + + +data-conversion API documentation + + + + + + + + + + + +
+ + +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/index.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/index.html new file mode 100644 index 0000000..f479377 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/index.html @@ -0,0 +1,76 @@ + + + + + + +data-conversion.interface API documentation + + + + + + + + + + + +
+ + +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/mainwindow.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/mainwindow.html new file mode 100644 index 0000000..45108ad --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/mainwindow.html @@ -0,0 +1,161 @@ + + + + + + +data-conversion.interface.mainwindow API documentation + + + + + + + + + + + +
+
+
+

Module data-conversion.interface.mainwindow

+
+
+
+ +Expand source code + +
from PySide6.QtWidgets import QMainWindow, QPushButton, QListWidget
+
+
+class MainWindow(QMainWindow):
+    """
+    Class written just for autocompletion and type hinting.
+
+    Lists dynamic attributes of the loaded window
+    so that PyCharm can know that the following attributes
+    exist in the loaded file.
+
+    The class is then used for type hinting in the
+    `WindowManager` class.
+
+    """
+    file_button: QPushButton
+    button_csv_export: QPushButton
+    button_txt_export: QPushButton
+    list_widget: QListWidget
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class MainWindow +(parent: Optional[PySide6.QtWidgets.QWidget] = None, flags: PySide6.QtCore.Qt.WindowFlags = Default(Qt.WindowFlags)) +
+
+

Class written just for autocompletion and type hinting.

+

Lists dynamic attributes of the loaded window +so that PyCharm can know that the following attributes +exist in the loaded file.

+

The class is then used for type hinting in the +WindowManager class.

+

init(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, flags: PySide6.QtCore.Qt.WindowFlags = Default(Qt.WindowFlags)) -> None

+

Initialize self. +See help(type(self)) for accurate signature.

+
+ +Expand source code + +
class MainWindow(QMainWindow):
+    """
+    Class written just for autocompletion and type hinting.
+
+    Lists dynamic attributes of the loaded window
+    so that PyCharm can know that the following attributes
+    exist in the loaded file.
+
+    The class is then used for type hinting in the
+    `WindowManager` class.
+
+    """
+    file_button: QPushButton
+    button_csv_export: QPushButton
+    button_txt_export: QPushButton
+    list_widget: QListWidget
+
+

Ancestors

+
    +
  • PySide6.QtWidgets.QMainWindow
  • +
  • PySide6.QtWidgets.QWidget
  • +
  • PySide6.QtCore.QObject
  • +
  • PySide6.QtGui.QPaintDevice
  • +
  • Shiboken.Object
  • +
+

Class variables

+
+
var button_csv_export : PySide6.QtWidgets.QPushButton
+
+
+
+
var button_txt_export : PySide6.QtWidgets.QPushButton
+
+
+
+
var file_button : PySide6.QtWidgets.QPushButton
+
+
+
+
var list_widget : PySide6.QtWidgets.QListWidget
+
+
+
+
var staticMetaObject
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/windowmanager.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/windowmanager.html new file mode 100644 index 0000000..bb4e049 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/interface/windowmanager.html @@ -0,0 +1,343 @@ + + + + + + +data-conversion.interface.windowmanager API documentation + + + + + + + + + + + +
+
+
+

Module data-conversion.interface.windowmanager

+
+
+
+ +Expand source code + +
from typing import Union
+
+from PySide6.QtUiTools import QUiLoader
+from PySide6.QtWidgets import QFileDialog, QWidget, QListWidgetItem
+
+from interface.mainwindow import MainWindow
+from loaders import CSVManager
+
+
+class WindowManager:
+    """
+    Class used to manage the Qt window and its associated data.
+
+    Attributes:
+        _window: Private, contains the main window.
+        _csv_manager: Private, holds a CSV manager.
+
+    """
+    _window: Union[QWidget, MainWindow] = None  # Qt window managed by this class
+    _csv_manager: CSVManager = None  # Object used to manage CSV data
+
+    def __init__(self):
+        """
+        Initialize our window manager.
+
+        """
+        loader = QUiLoader()
+        self._window = loader.load("files/designer/demo-dialog.ui")
+        # Once the window is loaded, connect actions to code
+        self.setup_actions()
+
+    def setup_actions(self):
+        """Connect actions of controls to methods."""
+        self._window.file_button.clicked.connect(self.on_file_select)
+        self._window.button_csv_export.clicked.connect(self.on_export_csv)
+
+    def on_file_select(self):
+        """
+        Action when the file button is clicked.
+
+        Shows a file select dialog to pick a CSV
+        and loads the CSV file in the CSVManager instance of the object.
+
+        """
+        filter_text = "CSV File (*.csv)"
+        selection: tuple = QFileDialog.getOpenFileName(self._window, "CSV File", "", filter_text)
+        path: str = selection[0]
+        if path:
+            self._csv_manager = CSVManager(path)
+            self._window.button_csv_export.setEnabled(True)
+            # Empty and enable the list widget
+            self._window.list_widget.clear()
+            self._window.list_widget.setEnabled(True)
+            for row in self._csv_manager.data:
+                item = QListWidgetItem(";".join(row))
+                self._window.list_widget.addItem(item)
+
+    def on_export_csv(self):
+        """
+        Action when the export to CSV button is clicked.
+
+        Shows a file select dialog to select a file destination.
+        The output file is then saved to the selected path.
+
+        """
+        filter_text = "Text File (*.txt)"
+        selection: tuple = QFileDialog.getSaveFileName(self._window, "Text File", "", filter_text)
+        path: str = selection[0]
+        if path:
+            self._csv_manager.export_text(selection[0])
+
+    def show(self):
+        """
+        Public method to show our window.
+
+        The window is loaded automatically at instanciation
+        in the `__init__` method.
+
+        """
+        self._window.show()
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class WindowManager +
+
+

Class used to manage the Qt window and its associated data.

+

Attributes

+
+
_window
+
Private, contains the main window.
+
_csv_manager
+
Private, holds a CSV manager.
+
+

Initialize our window manager.

+
+ +Expand source code + +
class WindowManager:
+    """
+    Class used to manage the Qt window and its associated data.
+
+    Attributes:
+        _window: Private, contains the main window.
+        _csv_manager: Private, holds a CSV manager.
+
+    """
+    _window: Union[QWidget, MainWindow] = None  # Qt window managed by this class
+    _csv_manager: CSVManager = None  # Object used to manage CSV data
+
+    def __init__(self):
+        """
+        Initialize our window manager.
+
+        """
+        loader = QUiLoader()
+        self._window = loader.load("files/designer/demo-dialog.ui")
+        # Once the window is loaded, connect actions to code
+        self.setup_actions()
+
+    def setup_actions(self):
+        """Connect actions of controls to methods."""
+        self._window.file_button.clicked.connect(self.on_file_select)
+        self._window.button_csv_export.clicked.connect(self.on_export_csv)
+
+    def on_file_select(self):
+        """
+        Action when the file button is clicked.
+
+        Shows a file select dialog to pick a CSV
+        and loads the CSV file in the CSVManager instance of the object.
+
+        """
+        filter_text = "CSV File (*.csv)"
+        selection: tuple = QFileDialog.getOpenFileName(self._window, "CSV File", "", filter_text)
+        path: str = selection[0]
+        if path:
+            self._csv_manager = CSVManager(path)
+            self._window.button_csv_export.setEnabled(True)
+            # Empty and enable the list widget
+            self._window.list_widget.clear()
+            self._window.list_widget.setEnabled(True)
+            for row in self._csv_manager.data:
+                item = QListWidgetItem(";".join(row))
+                self._window.list_widget.addItem(item)
+
+    def on_export_csv(self):
+        """
+        Action when the export to CSV button is clicked.
+
+        Shows a file select dialog to select a file destination.
+        The output file is then saved to the selected path.
+
+        """
+        filter_text = "Text File (*.txt)"
+        selection: tuple = QFileDialog.getSaveFileName(self._window, "Text File", "", filter_text)
+        path: str = selection[0]
+        if path:
+            self._csv_manager.export_text(selection[0])
+
+    def show(self):
+        """
+        Public method to show our window.
+
+        The window is loaded automatically at instanciation
+        in the `__init__` method.
+
+        """
+        self._window.show()
+
+

Methods

+
+
+def on_export_csv(self) +
+
+

Action when the export to CSV button is clicked.

+

Shows a file select dialog to select a file destination. +The output file is then saved to the selected path.

+
+ +Expand source code + +
def on_export_csv(self):
+    """
+    Action when the export to CSV button is clicked.
+
+    Shows a file select dialog to select a file destination.
+    The output file is then saved to the selected path.
+
+    """
+    filter_text = "Text File (*.txt)"
+    selection: tuple = QFileDialog.getSaveFileName(self._window, "Text File", "", filter_text)
+    path: str = selection[0]
+    if path:
+        self._csv_manager.export_text(selection[0])
+
+
+
+def on_file_select(self) +
+
+

Action when the file button is clicked.

+

Shows a file select dialog to pick a CSV +and loads the CSV file in the CSVManager instance of the object.

+
+ +Expand source code + +
def on_file_select(self):
+    """
+    Action when the file button is clicked.
+
+    Shows a file select dialog to pick a CSV
+    and loads the CSV file in the CSVManager instance of the object.
+
+    """
+    filter_text = "CSV File (*.csv)"
+    selection: tuple = QFileDialog.getOpenFileName(self._window, "CSV File", "", filter_text)
+    path: str = selection[0]
+    if path:
+        self._csv_manager = CSVManager(path)
+        self._window.button_csv_export.setEnabled(True)
+        # Empty and enable the list widget
+        self._window.list_widget.clear()
+        self._window.list_widget.setEnabled(True)
+        for row in self._csv_manager.data:
+            item = QListWidgetItem(";".join(row))
+            self._window.list_widget.addItem(item)
+
+
+
+def setup_actions(self) +
+
+

Connect actions of controls to methods.

+
+ +Expand source code + +
def setup_actions(self):
+    """Connect actions of controls to methods."""
+    self._window.file_button.clicked.connect(self.on_file_select)
+    self._window.button_csv_export.clicked.connect(self.on_export_csv)
+
+
+
+def show(self) +
+
+

Public method to show our window.

+

The window is loaded automatically at instanciation +in the __init__ method.

+
+ +Expand source code + +
def show(self):
+    """
+    Public method to show our window.
+
+    The window is loaded automatically at instanciation
+    in the `__init__` method.
+
+    """
+    self._window.show()
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/csvmanager.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/csvmanager.html new file mode 100644 index 0000000..710318a --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/csvmanager.html @@ -0,0 +1,327 @@ + + + + + + +data-conversion.loaders.csvmanager API documentation + + + + + + + + + + + +
+
+
+

Module data-conversion.loaders.csvmanager

+
+
+
+ +Expand source code + +
import csv
+
+
+class CSVManager:
+    """
+    Utility class to keep CSV data for export in other formats.
+
+    Attributes:
+        data: Contains loaded file data as a list of lists.
+
+    """
+
+    data: list = None
+
+    def __init__(self, url: str):
+        """
+        Initialize the object with a URL.
+
+        Args:
+            url: CSV URL to load from.
+
+        """
+        self.load(url)
+
+    def load(self, url: str, encoding: str = "iso8859-1"):
+        """
+        Load a CSV given its file path.
+
+        Args:
+            url: Path of the CSV file.
+            encoding: Codepage name of the text file.
+
+        """
+        with open(url, "r", encoding=encoding) as f:
+            reader = csv.reader(f, delimiter=",")
+            if self.data is None:
+                self.data = []
+            for row in reader:
+                self.data.append(row)
+
+    def export_text(self, url: str):
+        """
+        Save data as a text file.
+
+        Every column is save in its own line as an example.
+
+        Args:
+            url: Output file path.
+
+        """
+        with open(url, "w", encoding="utf-8") as file:
+            for row in self.data:
+                file.write("\n".join(row))
+
+    def export_csv(self, url: str):
+        """
+        Save data as a CSV file with semicolons.
+
+        Args:
+            url: Output file path.
+
+        """
+        with open(url, "w", encoding="utf-8") as file:
+            writer = csv.writer(file, delimiter=";")
+            for row in self.data:
+                writer.writerow(row)
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class CSVManager +(url: str) +
+
+

Utility class to keep CSV data for export in other formats.

+

Attributes

+
+
data
+
Contains loaded file data as a list of lists.
+
+

Initialize the object with a URL.

+

Args

+
+
url
+
CSV URL to load from.
+
+
+ +Expand source code + +
class CSVManager:
+    """
+    Utility class to keep CSV data for export in other formats.
+
+    Attributes:
+        data: Contains loaded file data as a list of lists.
+
+    """
+
+    data: list = None
+
+    def __init__(self, url: str):
+        """
+        Initialize the object with a URL.
+
+        Args:
+            url: CSV URL to load from.
+
+        """
+        self.load(url)
+
+    def load(self, url: str, encoding: str = "iso8859-1"):
+        """
+        Load a CSV given its file path.
+
+        Args:
+            url: Path of the CSV file.
+            encoding: Codepage name of the text file.
+
+        """
+        with open(url, "r", encoding=encoding) as f:
+            reader = csv.reader(f, delimiter=",")
+            if self.data is None:
+                self.data = []
+            for row in reader:
+                self.data.append(row)
+
+    def export_text(self, url: str):
+        """
+        Save data as a text file.
+
+        Every column is save in its own line as an example.
+
+        Args:
+            url: Output file path.
+
+        """
+        with open(url, "w", encoding="utf-8") as file:
+            for row in self.data:
+                file.write("\n".join(row))
+
+    def export_csv(self, url: str):
+        """
+        Save data as a CSV file with semicolons.
+
+        Args:
+            url: Output file path.
+
+        """
+        with open(url, "w", encoding="utf-8") as file:
+            writer = csv.writer(file, delimiter=";")
+            for row in self.data:
+                writer.writerow(row)
+
+

Class variables

+
+
var data : list
+
+
+
+
+

Methods

+
+
+def export_csv(self, url: str) +
+
+

Save data as a CSV file with semicolons.

+

Args

+
+
url
+
Output file path.
+
+
+ +Expand source code + +
def export_csv(self, url: str):
+    """
+    Save data as a CSV file with semicolons.
+
+    Args:
+        url: Output file path.
+
+    """
+    with open(url, "w", encoding="utf-8") as file:
+        writer = csv.writer(file, delimiter=";")
+        for row in self.data:
+            writer.writerow(row)
+
+
+
+def export_text(self, url: str) +
+
+

Save data as a text file.

+

Every column is save in its own line as an example.

+

Args

+
+
url
+
Output file path.
+
+
+ +Expand source code + +
def export_text(self, url: str):
+    """
+    Save data as a text file.
+
+    Every column is save in its own line as an example.
+
+    Args:
+        url: Output file path.
+
+    """
+    with open(url, "w", encoding="utf-8") as file:
+        for row in self.data:
+            file.write("\n".join(row))
+
+
+
+def load(self, url: str, encoding: str = 'iso8859-1') +
+
+

Load a CSV given its file path.

+

Args

+
+
url
+
Path of the CSV file.
+
encoding
+
Codepage name of the text file.
+
+
+ +Expand source code + +
def load(self, url: str, encoding: str = "iso8859-1"):
+    """
+    Load a CSV given its file path.
+
+    Args:
+        url: Path of the CSV file.
+        encoding: Codepage name of the text file.
+
+    """
+    with open(url, "r", encoding=encoding) as f:
+        reader = csv.reader(f, delimiter=",")
+        if self.data is None:
+            self.data = []
+        for row in reader:
+            self.data.append(row)
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/index.html b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/index.html new file mode 100644 index 0000000..eca5c53 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/data-conversion/loaders/index.html @@ -0,0 +1,71 @@ + + + + + + +data-conversion.loaders API documentation + + + + + + + + + + + +
+
+
+

Module data-conversion.loaders

+
+
+
+ +Expand source code + +
from .csvmanager import CSVManager  # Imports in the package so it can be imported from the package too
+
+
+
+

Sub-modules

+
+
data-conversion.loaders.csvmanager
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ + + \ No newline at end of file diff --git a/training/demos/10-graphical-ui/data-conversion-demo/documentation/includes/application.md b/training/demos/10-graphical-ui/data-conversion-demo/documentation/includes/application.md new file mode 100644 index 0000000..3a37694 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/documentation/includes/application.md @@ -0,0 +1,26 @@ +## Configuring your project for the application + +You will need to associate the code to a project if not +already done. If you don't have a project, just opening the folder +with PyCharm should suffice. + +However, you need to have a `virtualenv` for your project (for good +practice), that uses Python 3.6+. + +In this virtualenv, you'll have to install : + +- `pyside6` + +Note that Qt has issues with theming; if PySide6 is installed, using `pip` or +another medium, it won't follow the system theme. However, if PySide2 is +installed globally on the system (via `apt-get` or `pacman`), programs seem to +follow the system theme. One would then have to revert to importing from +`PySide2` instead of `PySide6` (with no other changes). + +## How to run the application + +The application is very simple to run in PyCharm. +To do it, right-click on the source file content pane, somewhere where +there is an empty space. + +Then, click the `Run ...`. diff --git a/training/demos/10-graphical-ui/data-conversion-demo/requirements.txt b/training/demos/10-graphical-ui/data-conversion-demo/requirements.txt new file mode 100644 index 0000000..9137a62 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/requirements.txt @@ -0,0 +1 @@ +pyside6 diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/application.py b/training/demos/10-graphical-ui/data-conversion-demo/source/application.py new file mode 100644 index 0000000..6c32c02 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/application.py @@ -0,0 +1,18 @@ +""" +Entry point for our demo application. + +Uses a "WindowManager" class holding the main window and the +CSV data manager used in it. + +.. include:: documentation/includes/application.md + +""" +from PySide6.QtWidgets import QApplication + +from interface import WindowManager # look at interface/__init__.py + +if __name__ == "__main__": + application = QApplication() + window_manager = WindowManager() + window_manager.show() + application.exec() diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/files/data/demo-csv.csv b/training/demos/10-graphical-ui/data-conversion-demo/source/files/data/demo-csv.csv new file mode 100644 index 0000000..65b43f5 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/files/data/demo-csv.csv @@ -0,0 +1,100 @@ +1,"Eldon Base for stackable storage shelf, platinum",Muhammed MacIntyre,3,-213.25,38.94,35,Nunavut,Storage & Organization,0.8 +2,"1.7 Cubic Foot Compact ""Cube"" Office Refrigerators",Barry French,293,457.81,208.16,68.02,Nunavut,Appliances,0.58 +3,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Barry French,293,46.71,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +4,R380,Clay Rozendal,483,1198.97,195.99,3.99,Nunavut,Telephones and Communication,0.58 +5,Holmes HEPA Air Purifier,Carlos Soltero,515,30.94,21.78,5.94,Nunavut,Appliances,0.5 +6,G.E. Longer-Life Indoor Recessed Floodlight Bulbs,Carlos Soltero,515,4.43,6.64,4.95,Nunavut,Office Furnishings,0.37 +7,"Angle-D Binders with Locking Rings, Label Holders",Carl Jackson,613,-54.04,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +8,"SAFCO Mobile Desk Side File, Wire Frame",Carl Jackson,613,127.70,42.76,6.22,Nunavut,Storage & Organization, +9,"SAFCO Commercial Wire Shelving, Black",Monica Federle,643,-695.26,138.14,35,Nunavut,Storage & Organization, +10,Xerox 198,Dorothy Badders,678,-226.36,4.98,8.33,Nunavut,Paper,0.38 +11,Xerox 1980,Neola Schneider,807,-166.85,4.28,6.18,Nunavut,Paper,0.4 +12,Advantus Map Pennant Flags and Round Head Tacks,Neola Schneider,807,-14.33,3.95,2,Nunavut,Rubber Bands,0.53 +13,Holmes HEPA Air Purifier,Carlos Daly,868,134.72,21.78,5.94,Nunavut,Appliances,0.5 +14,"DS/HD IBM Formatted Diskettes, 200/Pack - Staples",Carlos Daly,868,114.46,47.98,3.61,Nunavut,Computer Peripherals,0.71 +15,"Wilson Jones 1"" Hanging DublLock Ring Binders",Claudia Miner,933,-4.72,5.28,2.99,Nunavut,Binders and Binder Accessories,0.37 +16,Ultra Commercial Grade Dual Valve Door Closer,Neola Schneider,995,782.91,39.89,3.04,Nunavut,Office Furnishings,0.53 +17,"#10-4 1/8"" x 9 1/2"" Premium Diagonal Seam Envelopes",Allen Rosenblatt,998,93.80,15.74,1.39,Nunavut,Envelopes,0.4 +18,Hon 4-Shelf Metal Bookcases,Sylvia Foulston,1154,440.72,100.98,26.22,Nunavut,Bookcases,0.6 +19,"Lesro Sheffield Collection Coffee Table, End Table, Center Table, Corner Table",Sylvia Foulston,1154,-481.04,71.37,69,Nunavut,Tables,0.68 +20,g520,Jim Radford,1344,-11.68,65.99,5.26,Nunavut,Telephones and Communication,0.59 +21,LX 788,Jim Radford,1344,313.58,155.99,8.99,Nunavut,Telephones and Communication,0.58 +22,Avery 52,Carlos Soltero,1412,26.92,3.69,0.5,Nunavut,Labels,0.38 +23,Plymouth Boxed Rubber Bands by Plymouth,Carlos Soltero,1412,-5.77,4.71,0.7,Nunavut,Rubber Bands,0.8 +24,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Carl Ludwig,1539,-172.88,15.99,13.18,Nunavut,Binders and Binder Accessories,0.37 +25,"Maxell 3.5"" DS/HD IBM-Formatted Diskettes, 10/Pack",Carl Ludwig,1539,-144.55,4.89,4.93,Nunavut,Computer Peripherals,0.66 +26,Newell 335,Don Miller,1540,5.76,2.88,0.7,Nunavut,Pens & Art Supplies,0.56 +27,SANFORD Liquid Accent Tank-Style Highlighters,Annie Cyprus,1702,4.90,2.84,0.93,Nunavut,Pens & Art Supplies,0.54 +28,Canon PC940 Copier,Carl Ludwig,1761,-547.61,449.99,49,Nunavut,Copiers and Fax,0.38 +29,"Tenex Personal Project File with Scoop Front Design, Black",Carlos Soltero,1792,-5.45,13.48,4.51,Nunavut,Storage & Organization,0.59 +30,Col-Erase Pencils with Erasers,Grant Carroll,2275,41.67,6.08,1.17,Nunavut,Pens & Art Supplies,0.56 +31,"Imation 3.5"" DS/HD IBM Formatted Diskettes, 10/Pack",Don Miller,2277,-46.03,5.98,4.38,Nunavut,Computer Peripherals,0.75 +32,"White Dual Perf Computer Printout Paper, 2700 Sheets, 1 Part, Heavyweight, 20 lbs., 14 7/8 x 11",Don Miller,2277,33.67,40.99,19.99,Nunavut,Paper,0.36 +33,Self-Adhesive Address Labels for Typewriters by Universal,Alan Barnes,2532,140.01,7.31,0.49,Nunavut,Labels,0.38 +34,Accessory37,Alan Barnes,2532,-78.96,20.99,2.5,Nunavut,Telephones and Communication,0.81 +35,Fuji 5.2GB DVD-RAM,Jack Garza,2631,252.66,40.96,1.99,Nunavut,Computer Peripherals,0.55 +36,Bevis Steel Folding Chairs,Julia West,2757,-1766.01,95.95,74.35,Nunavut,Chairs & Chairmats,0.57 +37,Avery Binder Labels,Eugene Barchas,2791,-236.27,3.89,7.01,Nunavut,Binders and Binder Accessories,0.37 +38,Hon Every-Day Chair Series Swivel Task Chairs,Eugene Barchas,2791,80.44,120.98,30,Nunavut,Chairs & Chairmats,0.64 +39,"IBM Multi-Purpose Copy Paper, 8 1/2 x 11"", Case",Eugene Barchas,2791,118.94,30.98,5.76,Nunavut,Paper,0.4 +40,Global Troy Executive Leather Low-Back Tilter,Edward Hooks,2976,3424.22,500.98,26,Nunavut,Chairs & Chairmats,0.6 +41,XtraLife ClearVue Slant-D Ring Binders by Cardinal,Brad Eason,3232,-11.83,7.84,4.71,Nunavut,Binders and Binder Accessories,0.35 +42,Computer Printout Paper with Letter-Trim Perforations,Nicole Hansen,3524,52.35,18.97,9.03,Nunavut,Paper,0.37 +43,6160,Dorothy Wardle,3908,-180.20,115.99,2.5,Nunavut,Telephones and Communication,0.57 +44,Avery 49,Aaron Bergman,4132,1.32,2.88,0.5,Nunavut,Labels,0.36 +45,Hoover Portapower Portable Vacuum,Jim Radford,4612,-375.64,4.48,49,Nunavut,Appliances,0.6 +46,Timeport L7089,Annie Cyprus,4676,-104.25,125.99,7.69,Nunavut,Telephones and Communication,0.58 +47,Avery 510,Annie Cyprus,4676,85.96,3.75,0.5,Nunavut,Labels,0.37 +48,Xerox 1881,Annie Cyprus,4676,-8.38,12.28,6.47,Nunavut,Paper,0.38 +49,LX 788,Annie Cyprus,4676,1115.69,155.99,8.99,Nunavut,Telephones and Communication,0.58 +50,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Annie Cyprus,5284,-3.05,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +51,"Memorex 4.7GB DVD-RAM, 3/Pack",Clay Rozendal,5316,514.07,31.78,1.99,Nunavut,Computer Peripherals,0.42 +52,Unpadded Memo Slips,Don Jones,5409,-7.04,3.98,2.97,Nunavut,Paper,0.35 +53,"Adams Telephone Message Book W/Dividers/Space For Phone Numbers, 5 1/4""X8 1/2"", 300/Messages",Beth Thompson,5506,4.41,5.88,3.04,Nunavut,Paper,0.36 +54,"Eldon Expressions Desk Accessory, Wood Pencil Holder, Oak",Frank Price,5569,-0.06,9.65,6.22,Nunavut,Office Furnishings,0.55 +55,Bell Sonecor JB700 Caller ID,Michelle Lonsdale,5607,-50.33,7.99,5.03,Nunavut,Telephones and Communication,0.6 +56,Avery Arch Ring Binders,Ann Chong,5894,87.68,58.1,1.49,Nunavut,Binders and Binder Accessories,0.38 +57,APC 7 Outlet Network SurgeArrest Surge Protector,Ann Chong,5894,-68.22,80.48,4.5,Nunavut,Appliances,0.55 +58,"Deflect-o RollaMat Studded, Beveled Mat for Medium Pile Carpeting",Joy Bell,5925,-354.90,92.23,39.61,Nunavut,Office Furnishings,0.67 +59,Accessory4,Joy Bell,5925,-267.01,85.99,0.99,Nunavut,Telephones and Communication,0.85 +60,Personal Creations Ink Jet Cards and Labels,Skye Norling,6016,3.63,11.48,5.43,Nunavut,Paper,0.36 +61,High Speed Automatic Electric Letter Opener,Barry Weirich,6116,-1759.58,1637.53,24.49,Nunavut,"Scissors, Rulers and Trimmers",0.81 +62,Xerox 1966,Grant Carroll,6182,-116.79,6.48,6.65,Nunavut,Paper,0.36 +63,Xerox 213,Grant Carroll,6182,-67.28,6.48,7.86,Nunavut,Paper,0.37 +64,"Boston Electric Pencil Sharpener, Model 1818, Charcoal Black",Adrian Hane,6535,-19.33,28.15,8.99,Nunavut,Pens & Art Supplies,0.57 +65,Hammermill CopyPlus Copy Paper (20Lb. and 84 Bright),Skye Norling,6884,-61.21,4.98,4.75,Nunavut,Paper,0.36 +66,"Telephone Message Books with Fax/Mobile Section, 5 1/2"" x 3 3/16""",Skye Norling,6884,119.09,6.35,1.02,Nunavut,Paper,0.39 +67,Crate-A-Files,Andrew Gjertsen,6916,-141.27,10.9,7.46,Nunavut,Storage & Organization,0.59 +68,"Angle-D Binders with Locking Rings, Label Holders",Ralph Knight,6980,-77.28,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +69,"80 Minute CD-R Spindle, 100/Pack - Staples",Dorothy Wardle,6982,407.44,39.48,1.99,Nunavut,Computer Peripherals,0.54 +70,"Bush Westfield Collection Bookcases, Dark Cherry Finish, Fully Assembled",Dorothy Wardle,6982,-338.27,100.98,57.38,Nunavut,Bookcases,0.78 +71,12-1/2 Diameter Round Wall Clock,Dorothy Wardle,6982,52.56,19.98,10.49,Nunavut,Office Furnishings,0.49 +72,SAFCO Arco Folding Chair,Grant Carroll,7110,1902.24,276.2,24.49,Nunavut,Chairs & Chairmats, +73,"#10 White Business Envelopes,4 1/8 x 9 1/2",Barry Weirich,7430,353.20,15.67,1.39,Nunavut,Envelopes,0.38 +74,3M Office Air Cleaner,Beth Paige,7906,271.78,25.98,5.37,Nunavut,Appliances,0.5 +75,"Global Leather and Oak Executive Chair, Black",Sylvia Foulston,8391,-268.36,300.98,64.73,Nunavut,Chairs & Chairmats,0.56 +76,Xerox 1936,Nicole Hansen,8419,70.39,19.98,5.97,Nunavut,Paper,0.38 +77,Xerox 214,Nicole Hansen,8419,-86.62,6.48,7.03,Nunavut,Paper,0.37 +78,Carina Double Wide Media Storage Towers in Natural & Black,Nicole Hansen,8833,-846.73,80.98,35,Nunavut,Storage & Organization,0.81 +79,Staples General Use 3-Ring Binders,Beth Paige,8995,8.05,1.88,1.49,Nunavut,Binders and Binder Accessories,0.37 +80,Xerox 1904,Beth Paige,8995,-78.02,6.48,5.86,Northwest Territories,Paper,0.36 +81,Luxo Professional Combination Clamp-On Lamps,Beth Paige,8995,737.94,102.3,21.26,Northwest Territories,Office Furnishings,0.59 +82,Xerox 217,Beth Paige,8995,-191.28,6.48,8.19,Northwest Territories,Paper,0.37 +83,Revere Boxed Rubber Bands by Revere,Beth Paige,8995,-21.49,1.89,0.76,Northwest Territories,Rubber Bands,0.83 +84,"Acco Smartsocket Table Surge Protector, 6 Color-Coded Adapter Outlets",Sylvia Foulston,9126,884.08,62.05,3.99,Northwest Territories,Appliances,0.55 +85,"Tennsco Snap-Together Open Shelving Units, Starter Sets and Add-On Units",Bryan Davis,9127,-329.49,279.48,35,Northwest Territories,Storage & Organization,0.8 +86,Hon 4070 Series Pagoda Round Back Stacking Chairs,Joy Bell,9509,2825.15,320.98,58.95,Northwest Territories,Chairs & Chairmats,0.57 +87,Xerox 1887,Joy Bell,9509,2.13,18.97,5.21,Northwest Territories,Paper,0.37 +88,Xerox 1891,Joy Bell,9509,707.15,48.91,5.81,Northwest Territories,Paper,0.38 +89,Avery 506,Alan Barnes,9763,75.13,4.13,0.5,Northwest Territories,Labels,0.39 +90,"Bush Heritage Pine Collection 5-Shelf Bookcase, Albany Pine Finish, *Special Order",Grant Carroll,9927,-270.63,140.98,53.48,Northwest Territories,Bookcases,0.65 +91,"Lifetime Advantage Folding Chairs, 4/Carton",Grant Carroll,9927,3387.35,218.08,18.06,Northwest Territories,Chairs & Chairmats,0.57 +92,Microsoft Natural Multimedia Keyboard,Grant Carroll,9927,-82.16,50.98,6.5,Northwest Territories,Computer Peripherals,0.73 +93,"Staples Wirebound Steno Books, 6"" x 9"", 12/Pack",Delfina Latchford,10022,-3.88,10.14,2.27,Northwest Territories,Paper,0.36 +94,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Don Jones,10437,-191.22,15.99,13.18,Northwest Territories,Binders and Binder Accessories,0.37 +95,Bevis Boat-Shaped Conference Table,Doug Bickford,10499,31.21,262.11,62.74,Northwest Territories,Tables,0.75 +96,"Linden 12"" Wall Clock With Oak Frame",Doug Bickford,10535,-44.14,33.98,19.99,Northwest Territories,Office Furnishings,0.55 +97,Newell 326,Doug Bickford,10535,-0.79,1.76,0.7,Northwest Territories,Pens & Art Supplies,0.56 +98,Prismacolor Color Pencil Set,Jamie Kunitz,10789,76.42,19.84,4.1,Northwest Territories,Pens & Art Supplies,0.44 +99,Xerox Blank Computer Paper,Anthony Johnson,10791,93.36,19.98,5.77,Northwest Territories,Paper,0.38 +100,600 Series Flip,Ralph Knight,10945,4.22,95.99,8.99,Northwest Territories,Telephones and Communication,0.57 diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/files/designer/demo-dialog.ui b/training/demos/10-graphical-ui/data-conversion-demo/source/files/designer/demo-dialog.ui new file mode 100644 index 0000000..2fb69e4 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/files/designer/demo-dialog.ui @@ -0,0 +1,131 @@ + + + MainWindow + + + + 0 + 0 + 625 + 438 + + + + + 0 + 0 + + + + Conversion de données CSV + + + + ../../../../../../../../../.designer/backup../../../../../../../../../.designer/backup + + + + + + + + + + + Sélectionnez un CSV + + + + + + + + 0 + 0 + + + + Cliquez pour sélectionner + + + + ../../../../../../../../../.designer/backup../../../../../../../../../.designer/backup + + + + + + + + + + + Veuillez sélectionner un fichier CSV valide pour continuer... + + + + + + + false + + + + + + + + + false + + + Exporter en CSV + + + + + + + false + + + Exporter en texte + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + 0 + 0 + 625 + 26 + + + + + + + + diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/interface/__init__.py b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/__init__.py new file mode 100644 index 0000000..fe9b2b3 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/__init__.py @@ -0,0 +1 @@ +from .windowmanager import WindowManager diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/interface/mainwindow.py b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/mainwindow.py new file mode 100644 index 0000000..3dabda5 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/mainwindow.py @@ -0,0 +1,19 @@ +from PySide6.QtWidgets import QMainWindow, QPushButton, QListWidget + + +class MainWindow(QMainWindow): + """ + Class written just for autocompletion and type hinting. + + Lists dynamic attributes of the loaded window + so that PyCharm can know that the following attributes + exist in the loaded file. + + The class is then used for type hinting in the + `WindowManager` class. + + """ + file_button: QPushButton + button_csv_export: QPushButton + button_txt_export: QPushButton + list_widget: QListWidget diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/interface/windowmanager.py b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/windowmanager.py new file mode 100644 index 0000000..db1ee74 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/interface/windowmanager.py @@ -0,0 +1,81 @@ +from typing import Union + +from PySide6.QtUiTools import QUiLoader +from PySide6.QtWidgets import QFileDialog, QWidget, QListWidgetItem + +from interface.mainwindow import MainWindow +from loaders import CSVManager + + +class WindowManager: + """ + Class used to manage the Qt window and its associated data. + + Attributes: + _window: Private, contains the main window. + _csv_manager: Private, holds a CSV manager. + + """ + _window: Union[QWidget, MainWindow] = None # Qt window managed by this class + _csv_manager: CSVManager = None # Object used to manage CSV data + + def __init__(self): + """ + Initialize our window manager. + + """ + loader = QUiLoader() + self._window = loader.load("files/designer/demo-dialog.ui") + # Once the window is loaded, connect actions to code + self.setup_actions() + + def setup_actions(self): + """Connect actions of controls to methods.""" + self._window.file_button.clicked.connect(self.on_file_select) + self._window.button_csv_export.clicked.connect(self.on_export_csv) + + def on_file_select(self): + """ + Action when the file button is clicked. + + Shows a file select dialog to pick a CSV + and loads the CSV file in the CSVManager instance of the object. + + """ + filter_text = "CSV File (*.csv)" + selection: tuple = QFileDialog.getOpenFileName(self._window, "CSV File", "", filter_text) + path: str = selection[0] + if path: + self._csv_manager = CSVManager(path) + self._window.button_csv_export.setEnabled(True) + # Empty list items and enable the list widget + self._window.list_widget.clear() + self._window.list_widget.setEnabled(True) + # Add rows in the list widget containing CSV rows + for row in self._csv_manager.data: + item = QListWidgetItem(";".join(row)) + self._window.list_widget.addItem(item) + + def on_export_csv(self): + """ + Action when the export to CSV button is clicked. + + Shows a file select dialog to select a file destination. + The output file is then saved to the selected path. + + """ + filter_text = "Text File (*.txt)" + selection: tuple = QFileDialog.getSaveFileName(self._window, "Text File", "", filter_text) + path: str = selection[0] + if path: + self._csv_manager.export_text(selection[0]) + + def show(self): + """ + Public method to show our window. + + The window is loaded automatically at instanciation + in the `__init__` method. + + """ + self._window.show() diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/__init__.py b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/__init__.py new file mode 100644 index 0000000..866e6be --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/__init__.py @@ -0,0 +1 @@ +from .csvmanager import CSVManager # Imports in the package so it can be imported from the package too diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/basemanager.py b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/basemanager.py new file mode 100644 index 0000000..bf04502 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/basemanager.py @@ -0,0 +1,16 @@ +from abc import ABC, abstractmethod +from loaders.formats import DataFormat + + +class BaseDataManager(ABC): + """Base class for data managers.""" + + @abstractmethod + def load(self, url: str, encoding: str = "iso8859-1"): + """Load data for the manager.""" + pass + + @abstractmethod + def export(self, url: str, fmt: DataFormat): + """Export data in a specific format.""" + pass diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/csvmanager.py b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/csvmanager.py new file mode 100644 index 0000000..100e62d --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/csvmanager.py @@ -0,0 +1,78 @@ +import csv + +from loaders.basemanager import BaseDataManager +from loaders.formats import DataFormat + + +class CSVManager(BaseDataManager): + """ + Utility class to keep CSV data for export in other formats. + + Attributes: + data: Contains loaded file data as a list of lists. + + """ + + data: list = None + + def __init__(self, url: str): + """ + Initialize the object with a URL. + + Args: + url: CSV URL to load from. + + """ + self.load(url) + + def load(self, url: str, encoding: str = "iso8859-1"): + """ + Load a CSV given its file path. + + Args: + url: Path of the CSV file. + encoding: Codepage name of the text file. + + """ + with open(url, "r", encoding=encoding) as f: + reader = csv.reader(f, delimiter=",") + if self.data is None: + self.data = [] + for row in reader: + self.data.append(row) + + def export(self, url: str, fmt: DataFormat): + """Official method to export data.""" + if fmt is DataFormat.TEXT: + self.export_text(url) + elif fmt is DataFormat.CSV: + self.export_csv(url) + else: + raise ValueError(f"{fmt}: unsupported format.") + + def export_text(self, url: str): + """ + Save data as a text file. + + Every column is save in its own line as an example. + + Args: + url: Output file path. + + """ + with open(url, "w", encoding="utf-8") as file: + for row in self.data: + file.write("\n".join(row)) + + def export_csv(self, url: str): + """ + Save data as a CSV file with semicolons. + + Args: + url: Output file path. + + """ + with open(url, "w", encoding="utf-8") as file: + writer = csv.writer(file, delimiter=";") + for row in self.data: + writer.writerow(row) diff --git a/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/formats.py b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/formats.py new file mode 100644 index 0000000..1ad5a22 --- /dev/null +++ b/training/demos/10-graphical-ui/data-conversion-demo/source/loaders/formats.py @@ -0,0 +1,7 @@ +from enum import IntEnum + + +class DataFormat(IntEnum): + """Supported formats enumeration.""" + CSV = 0 + TEXT = 1 diff --git a/training/demos/10-graphical-ui/simple-list-widget/requirements.txt b/training/demos/10-graphical-ui/simple-list-widget/requirements.txt new file mode 100644 index 0000000..9137a62 --- /dev/null +++ b/training/demos/10-graphical-ui/simple-list-widget/requirements.txt @@ -0,0 +1 @@ +pyside6 diff --git a/training/demos/10-graphical-ui/simple-list-widget/source/application.py b/training/demos/10-graphical-ui/simple-list-widget/source/application.py new file mode 100644 index 0000000..4ae4e9c --- /dev/null +++ b/training/demos/10-graphical-ui/simple-list-widget/source/application.py @@ -0,0 +1,21 @@ +from PySide6.QtGui import QIcon +from PySide6.QtUiTools import QUiLoader +from PySide6.QtWidgets import QApplication, QListWidget, QListWidgetItem, QMainWindow + +if __name__ == "__main__": + application = QApplication() + # Load main window with list widget from Designer file + window: QMainWindow = QUiLoader().load("files/list-widget.ui") + list1: QListWidget = window.list1 + # Add icon + sleep_icon = QIcon.fromTheme("text-x-python") + for i in range(20): + item = QListWidgetItem(sleep_icon, f"Élément {i}") + list1.addItem(item) + + def on_clicked(list_item: QListWidgetItem): + print(list_item.text()) + + list1.itemClicked.connect(on_clicked) + window.show() + application.exec() diff --git a/training/demos/10-graphical-ui/simple-list-widget/source/files/list-widget.ui b/training/demos/10-graphical-ui/simple-list-widget/source/files/list-widget.ui new file mode 100644 index 0000000..7f8a20a --- /dev/null +++ b/training/demos/10-graphical-ui/simple-list-widget/source/files/list-widget.ui @@ -0,0 +1,44 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + List widget demonstration + + + + + + + + + + + + + + + + + + + 0 + 0 + 800 + 26 + + + + + + + + diff --git a/training/demos/12-logging/logging-hierarchy/source/application.py b/training/demos/12-logging/logging-hierarchy/source/application.py new file mode 100644 index 0000000..31d56c9 --- /dev/null +++ b/training/demos/12-logging/logging-hierarchy/source/application.py @@ -0,0 +1,10 @@ +from data.csvmanager import CSVManager +from data.basemanager import BaseManager + + +if __name__ == '__main__': + csv1 = CSVManager("files/demo-csv.csv") + csv2 = CSVManager("files/demo-csv-incorrect.csv") + base1 = BaseManager("files/demo-csv.csv") + print(csv1.get_info()) + print(csv2.get_info()) diff --git a/training/demos/12-logging/logging-hierarchy/source/data/__init__.py b/training/demos/12-logging/logging-hierarchy/source/data/__init__.py new file mode 100644 index 0000000..07828c5 --- /dev/null +++ b/training/demos/12-logging/logging-hierarchy/source/data/__init__.py @@ -0,0 +1,14 @@ +import logging +import sys + +logger = logging.getLogger("data") + +# Configure the main logger for the data package +if not logger.handlers: + handler = logging.StreamHandler(sys.stdout) + formatting = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") + handler.setFormatter(formatting) + handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + logger.debug("Data logger registered.") diff --git a/training/demos/12-logging/logging-hierarchy/source/data/basemanager.py b/training/demos/12-logging/logging-hierarchy/source/data/basemanager.py new file mode 100644 index 0000000..740e12d --- /dev/null +++ b/training/demos/12-logging/logging-hierarchy/source/data/basemanager.py @@ -0,0 +1,24 @@ +import logging +from os.path import getsize + + +logger = logging.getLogger("data.basemanager") + + +class BaseManager: + """Base data file manager.""" + + def __init__(self, path: str): + self._path = path + logger.info(f"New file manager initialized for file {path}") + + def get_info(self) -> dict: + """Get basic information about the file.""" + try: + data = {"size": getsize(self._path)} + return data + except IOError: + logger.error("Could not get file size.") + return {"size": -1} + + diff --git a/training/demos/12-logging/logging-hierarchy/source/data/csvmanager.py b/training/demos/12-logging/logging-hierarchy/source/data/csvmanager.py new file mode 100644 index 0000000..ab1bd52 --- /dev/null +++ b/training/demos/12-logging/logging-hierarchy/source/data/csvmanager.py @@ -0,0 +1,28 @@ +import csv +import logging + +from data.basemanager import BaseManager + + +logger = logging.getLogger("data.csvmanager") + + +class CSVManager(BaseManager): + """Data manager for CSV files.""" + + def get_info(self) -> dict: + data = super().get_info() + try: + with open(self._path, "r", encoding="utf-8") as file: + reader = csv.reader(file) + for idx, _ in enumerate(reader): + pass + data["rows"] = idx + return data + except IOError: + logger.error("Could not decode CSV, IO error occurred.") + return data + except UnicodeDecodeError: + logger.error("CSV is not encoded in UTF8, skipping.") + return data + diff --git a/training/demos/12-logging/logging-hierarchy/source/files/demo-csv.csv b/training/demos/12-logging/logging-hierarchy/source/files/demo-csv.csv new file mode 100644 index 0000000..65b43f5 --- /dev/null +++ b/training/demos/12-logging/logging-hierarchy/source/files/demo-csv.csv @@ -0,0 +1,100 @@ +1,"Eldon Base for stackable storage shelf, platinum",Muhammed MacIntyre,3,-213.25,38.94,35,Nunavut,Storage & Organization,0.8 +2,"1.7 Cubic Foot Compact ""Cube"" Office Refrigerators",Barry French,293,457.81,208.16,68.02,Nunavut,Appliances,0.58 +3,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Barry French,293,46.71,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +4,R380,Clay Rozendal,483,1198.97,195.99,3.99,Nunavut,Telephones and Communication,0.58 +5,Holmes HEPA Air Purifier,Carlos Soltero,515,30.94,21.78,5.94,Nunavut,Appliances,0.5 +6,G.E. Longer-Life Indoor Recessed Floodlight Bulbs,Carlos Soltero,515,4.43,6.64,4.95,Nunavut,Office Furnishings,0.37 +7,"Angle-D Binders with Locking Rings, Label Holders",Carl Jackson,613,-54.04,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +8,"SAFCO Mobile Desk Side File, Wire Frame",Carl Jackson,613,127.70,42.76,6.22,Nunavut,Storage & Organization, +9,"SAFCO Commercial Wire Shelving, Black",Monica Federle,643,-695.26,138.14,35,Nunavut,Storage & Organization, +10,Xerox 198,Dorothy Badders,678,-226.36,4.98,8.33,Nunavut,Paper,0.38 +11,Xerox 1980,Neola Schneider,807,-166.85,4.28,6.18,Nunavut,Paper,0.4 +12,Advantus Map Pennant Flags and Round Head Tacks,Neola Schneider,807,-14.33,3.95,2,Nunavut,Rubber Bands,0.53 +13,Holmes HEPA Air Purifier,Carlos Daly,868,134.72,21.78,5.94,Nunavut,Appliances,0.5 +14,"DS/HD IBM Formatted Diskettes, 200/Pack - Staples",Carlos Daly,868,114.46,47.98,3.61,Nunavut,Computer Peripherals,0.71 +15,"Wilson Jones 1"" Hanging DublLock Ring Binders",Claudia Miner,933,-4.72,5.28,2.99,Nunavut,Binders and Binder Accessories,0.37 +16,Ultra Commercial Grade Dual Valve Door Closer,Neola Schneider,995,782.91,39.89,3.04,Nunavut,Office Furnishings,0.53 +17,"#10-4 1/8"" x 9 1/2"" Premium Diagonal Seam Envelopes",Allen Rosenblatt,998,93.80,15.74,1.39,Nunavut,Envelopes,0.4 +18,Hon 4-Shelf Metal Bookcases,Sylvia Foulston,1154,440.72,100.98,26.22,Nunavut,Bookcases,0.6 +19,"Lesro Sheffield Collection Coffee Table, End Table, Center Table, Corner Table",Sylvia Foulston,1154,-481.04,71.37,69,Nunavut,Tables,0.68 +20,g520,Jim Radford,1344,-11.68,65.99,5.26,Nunavut,Telephones and Communication,0.59 +21,LX 788,Jim Radford,1344,313.58,155.99,8.99,Nunavut,Telephones and Communication,0.58 +22,Avery 52,Carlos Soltero,1412,26.92,3.69,0.5,Nunavut,Labels,0.38 +23,Plymouth Boxed Rubber Bands by Plymouth,Carlos Soltero,1412,-5.77,4.71,0.7,Nunavut,Rubber Bands,0.8 +24,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Carl Ludwig,1539,-172.88,15.99,13.18,Nunavut,Binders and Binder Accessories,0.37 +25,"Maxell 3.5"" DS/HD IBM-Formatted Diskettes, 10/Pack",Carl Ludwig,1539,-144.55,4.89,4.93,Nunavut,Computer Peripherals,0.66 +26,Newell 335,Don Miller,1540,5.76,2.88,0.7,Nunavut,Pens & Art Supplies,0.56 +27,SANFORD Liquid Accent Tank-Style Highlighters,Annie Cyprus,1702,4.90,2.84,0.93,Nunavut,Pens & Art Supplies,0.54 +28,Canon PC940 Copier,Carl Ludwig,1761,-547.61,449.99,49,Nunavut,Copiers and Fax,0.38 +29,"Tenex Personal Project File with Scoop Front Design, Black",Carlos Soltero,1792,-5.45,13.48,4.51,Nunavut,Storage & Organization,0.59 +30,Col-Erase Pencils with Erasers,Grant Carroll,2275,41.67,6.08,1.17,Nunavut,Pens & Art Supplies,0.56 +31,"Imation 3.5"" DS/HD IBM Formatted Diskettes, 10/Pack",Don Miller,2277,-46.03,5.98,4.38,Nunavut,Computer Peripherals,0.75 +32,"White Dual Perf Computer Printout Paper, 2700 Sheets, 1 Part, Heavyweight, 20 lbs., 14 7/8 x 11",Don Miller,2277,33.67,40.99,19.99,Nunavut,Paper,0.36 +33,Self-Adhesive Address Labels for Typewriters by Universal,Alan Barnes,2532,140.01,7.31,0.49,Nunavut,Labels,0.38 +34,Accessory37,Alan Barnes,2532,-78.96,20.99,2.5,Nunavut,Telephones and Communication,0.81 +35,Fuji 5.2GB DVD-RAM,Jack Garza,2631,252.66,40.96,1.99,Nunavut,Computer Peripherals,0.55 +36,Bevis Steel Folding Chairs,Julia West,2757,-1766.01,95.95,74.35,Nunavut,Chairs & Chairmats,0.57 +37,Avery Binder Labels,Eugene Barchas,2791,-236.27,3.89,7.01,Nunavut,Binders and Binder Accessories,0.37 +38,Hon Every-Day Chair Series Swivel Task Chairs,Eugene Barchas,2791,80.44,120.98,30,Nunavut,Chairs & Chairmats,0.64 +39,"IBM Multi-Purpose Copy Paper, 8 1/2 x 11"", Case",Eugene Barchas,2791,118.94,30.98,5.76,Nunavut,Paper,0.4 +40,Global Troy Executive Leather Low-Back Tilter,Edward Hooks,2976,3424.22,500.98,26,Nunavut,Chairs & Chairmats,0.6 +41,XtraLife ClearVue Slant-D Ring Binders by Cardinal,Brad Eason,3232,-11.83,7.84,4.71,Nunavut,Binders and Binder Accessories,0.35 +42,Computer Printout Paper with Letter-Trim Perforations,Nicole Hansen,3524,52.35,18.97,9.03,Nunavut,Paper,0.37 +43,6160,Dorothy Wardle,3908,-180.20,115.99,2.5,Nunavut,Telephones and Communication,0.57 +44,Avery 49,Aaron Bergman,4132,1.32,2.88,0.5,Nunavut,Labels,0.36 +45,Hoover Portapower Portable Vacuum,Jim Radford,4612,-375.64,4.48,49,Nunavut,Appliances,0.6 +46,Timeport L7089,Annie Cyprus,4676,-104.25,125.99,7.69,Nunavut,Telephones and Communication,0.58 +47,Avery 510,Annie Cyprus,4676,85.96,3.75,0.5,Nunavut,Labels,0.37 +48,Xerox 1881,Annie Cyprus,4676,-8.38,12.28,6.47,Nunavut,Paper,0.38 +49,LX 788,Annie Cyprus,4676,1115.69,155.99,8.99,Nunavut,Telephones and Communication,0.58 +50,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Annie Cyprus,5284,-3.05,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +51,"Memorex 4.7GB DVD-RAM, 3/Pack",Clay Rozendal,5316,514.07,31.78,1.99,Nunavut,Computer Peripherals,0.42 +52,Unpadded Memo Slips,Don Jones,5409,-7.04,3.98,2.97,Nunavut,Paper,0.35 +53,"Adams Telephone Message Book W/Dividers/Space For Phone Numbers, 5 1/4""X8 1/2"", 300/Messages",Beth Thompson,5506,4.41,5.88,3.04,Nunavut,Paper,0.36 +54,"Eldon Expressions Desk Accessory, Wood Pencil Holder, Oak",Frank Price,5569,-0.06,9.65,6.22,Nunavut,Office Furnishings,0.55 +55,Bell Sonecor JB700 Caller ID,Michelle Lonsdale,5607,-50.33,7.99,5.03,Nunavut,Telephones and Communication,0.6 +56,Avery Arch Ring Binders,Ann Chong,5894,87.68,58.1,1.49,Nunavut,Binders and Binder Accessories,0.38 +57,APC 7 Outlet Network SurgeArrest Surge Protector,Ann Chong,5894,-68.22,80.48,4.5,Nunavut,Appliances,0.55 +58,"Deflect-o RollaMat Studded, Beveled Mat for Medium Pile Carpeting",Joy Bell,5925,-354.90,92.23,39.61,Nunavut,Office Furnishings,0.67 +59,Accessory4,Joy Bell,5925,-267.01,85.99,0.99,Nunavut,Telephones and Communication,0.85 +60,Personal Creations Ink Jet Cards and Labels,Skye Norling,6016,3.63,11.48,5.43,Nunavut,Paper,0.36 +61,High Speed Automatic Electric Letter Opener,Barry Weirich,6116,-1759.58,1637.53,24.49,Nunavut,"Scissors, Rulers and Trimmers",0.81 +62,Xerox 1966,Grant Carroll,6182,-116.79,6.48,6.65,Nunavut,Paper,0.36 +63,Xerox 213,Grant Carroll,6182,-67.28,6.48,7.86,Nunavut,Paper,0.37 +64,"Boston Electric Pencil Sharpener, Model 1818, Charcoal Black",Adrian Hane,6535,-19.33,28.15,8.99,Nunavut,Pens & Art Supplies,0.57 +65,Hammermill CopyPlus Copy Paper (20Lb. and 84 Bright),Skye Norling,6884,-61.21,4.98,4.75,Nunavut,Paper,0.36 +66,"Telephone Message Books with Fax/Mobile Section, 5 1/2"" x 3 3/16""",Skye Norling,6884,119.09,6.35,1.02,Nunavut,Paper,0.39 +67,Crate-A-Files,Andrew Gjertsen,6916,-141.27,10.9,7.46,Nunavut,Storage & Organization,0.59 +68,"Angle-D Binders with Locking Rings, Label Holders",Ralph Knight,6980,-77.28,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +69,"80 Minute CD-R Spindle, 100/Pack - Staples",Dorothy Wardle,6982,407.44,39.48,1.99,Nunavut,Computer Peripherals,0.54 +70,"Bush Westfield Collection Bookcases, Dark Cherry Finish, Fully Assembled",Dorothy Wardle,6982,-338.27,100.98,57.38,Nunavut,Bookcases,0.78 +71,12-1/2 Diameter Round Wall Clock,Dorothy Wardle,6982,52.56,19.98,10.49,Nunavut,Office Furnishings,0.49 +72,SAFCO Arco Folding Chair,Grant Carroll,7110,1902.24,276.2,24.49,Nunavut,Chairs & Chairmats, +73,"#10 White Business Envelopes,4 1/8 x 9 1/2",Barry Weirich,7430,353.20,15.67,1.39,Nunavut,Envelopes,0.38 +74,3M Office Air Cleaner,Beth Paige,7906,271.78,25.98,5.37,Nunavut,Appliances,0.5 +75,"Global Leather and Oak Executive Chair, Black",Sylvia Foulston,8391,-268.36,300.98,64.73,Nunavut,Chairs & Chairmats,0.56 +76,Xerox 1936,Nicole Hansen,8419,70.39,19.98,5.97,Nunavut,Paper,0.38 +77,Xerox 214,Nicole Hansen,8419,-86.62,6.48,7.03,Nunavut,Paper,0.37 +78,Carina Double Wide Media Storage Towers in Natural & Black,Nicole Hansen,8833,-846.73,80.98,35,Nunavut,Storage & Organization,0.81 +79,Staples General Use 3-Ring Binders,Beth Paige,8995,8.05,1.88,1.49,Nunavut,Binders and Binder Accessories,0.37 +80,Xerox 1904,Beth Paige,8995,-78.02,6.48,5.86,Northwest Territories,Paper,0.36 +81,Luxo Professional Combination Clamp-On Lamps,Beth Paige,8995,737.94,102.3,21.26,Northwest Territories,Office Furnishings,0.59 +82,Xerox 217,Beth Paige,8995,-191.28,6.48,8.19,Northwest Territories,Paper,0.37 +83,Revere Boxed Rubber Bands by Revere,Beth Paige,8995,-21.49,1.89,0.76,Northwest Territories,Rubber Bands,0.83 +84,"Acco Smartsocket Table Surge Protector, 6 Color-Coded Adapter Outlets",Sylvia Foulston,9126,884.08,62.05,3.99,Northwest Territories,Appliances,0.55 +85,"Tennsco Snap-Together Open Shelving Units, Starter Sets and Add-On Units",Bryan Davis,9127,-329.49,279.48,35,Northwest Territories,Storage & Organization,0.8 +86,Hon 4070 Series Pagoda Round Back Stacking Chairs,Joy Bell,9509,2825.15,320.98,58.95,Northwest Territories,Chairs & Chairmats,0.57 +87,Xerox 1887,Joy Bell,9509,2.13,18.97,5.21,Northwest Territories,Paper,0.37 +88,Xerox 1891,Joy Bell,9509,707.15,48.91,5.81,Northwest Territories,Paper,0.38 +89,Avery 506,Alan Barnes,9763,75.13,4.13,0.5,Northwest Territories,Labels,0.39 +90,"Bush Heritage Pine Collection 5-Shelf Bookcase, Albany Pine Finish, *Special Order",Grant Carroll,9927,-270.63,140.98,53.48,Northwest Territories,Bookcases,0.65 +91,"Lifetime Advantage Folding Chairs, 4/Carton",Grant Carroll,9927,3387.35,218.08,18.06,Northwest Territories,Chairs & Chairmats,0.57 +92,Microsoft Natural Multimedia Keyboard,Grant Carroll,9927,-82.16,50.98,6.5,Northwest Territories,Computer Peripherals,0.73 +93,"Staples Wirebound Steno Books, 6"" x 9"", 12/Pack",Delfina Latchford,10022,-3.88,10.14,2.27,Northwest Territories,Paper,0.36 +94,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Don Jones,10437,-191.22,15.99,13.18,Northwest Territories,Binders and Binder Accessories,0.37 +95,Bevis Boat-Shaped Conference Table,Doug Bickford,10499,31.21,262.11,62.74,Northwest Territories,Tables,0.75 +96,"Linden 12"" Wall Clock With Oak Frame",Doug Bickford,10535,-44.14,33.98,19.99,Northwest Territories,Office Furnishings,0.55 +97,Newell 326,Doug Bickford,10535,-0.79,1.76,0.7,Northwest Territories,Pens & Art Supplies,0.56 +98,Prismacolor Color Pencil Set,Jamie Kunitz,10789,76.42,19.84,4.1,Northwest Territories,Pens & Art Supplies,0.44 +99,Xerox Blank Computer Paper,Anthony Johnson,10791,93.36,19.98,5.77,Northwest Territories,Paper,0.38 +100,600 Series Flip,Ralph Knight,10945,4.22,95.99,8.99,Northwest Territories,Telephones and Communication,0.57 diff --git a/training/demos/99-extra/commandline-arguments/source/argparse_demo.py b/training/demos/99-extra/commandline-arguments/source/argparse_demo.py new file mode 100644 index 0000000..e994066 --- /dev/null +++ b/training/demos/99-extra/commandline-arguments/source/argparse_demo.py @@ -0,0 +1,13 @@ +import argparse + +if __name__ == "__main__": + # Argparse demo: accept running this script with options like command tools. + parser = argparse.ArgumentParser(description="Demonstration argument parser") + parser.add_argument("--plop", required=True, help="Argument inutile", type=int) + parser.add_argument("--plip", required=False, default=None, help="Autre argument inutile", type=int) + options = parser.parse_args() + + print(options) + print(options.plip) + print(options.plop) + print(options.__dict__) diff --git a/training/exercices/02-language-basics/01-prints.asciidoc b/training/exercices/02-language-basics/01-prints.asciidoc new file mode 100644 index 0000000..4009b59 --- /dev/null +++ b/training/exercices/02-language-basics/01-prints.asciidoc @@ -0,0 +1,32 @@ += Exercices sur la fonction `print()` + +== Exercice 1 + +Affichez dans la console le texte suivant : + +- La rue Rostand, +- `3 espaces` se trouve au +- Feu à droite + +== Exercice 2 + +La fonction `print()` accepte plusieurs arguments, dont les valeurs sont affichées sur la même ligne, et par défaut séparés par un espace. + +*La syntaxe est la suivante* : `print("a", "b", "c", 19)` + +Affichez, en imitant cette syntaxe, le texte suivant : + +* Hauts les cœurs ! + +(sous Linux, le e dans l'o s'obtient avec la combinaison de touches `Alt Gr + O`. Sous Windows, `Alt + 339` devrait donner le même résultat) + +== Exercice A1 + +La fonction `print()` accepte des arguments avec des noms spécifiques, dont `sep` et `end`. `sep` permet de désigner quelle chaîne sépare les arguments à afficher, et `end` permet de préciser par quelle chaîne terminer le `print`. +Par défaut, `sep=" "` et `end="\n"`. La fonction s'utiliserait ainsi : + +```python +# Ne sépare pas les éléments via un espace et passe deux fois +# à la ligne à la fin du print. +print("1", "2", "3", sep="", end="\n\n") +``` diff --git a/training/exercices/02-language-basics/02-variables.asciidoc b/training/exercices/02-language-basics/02-variables.asciidoc new file mode 100644 index 0000000..36f7a27 --- /dev/null +++ b/training/exercices/02-language-basics/02-variables.asciidoc @@ -0,0 +1,70 @@ += Variables + +--- + +== Exercice 1 + +- Déclarez trois variables, avec des noms corrects, contenant : +* Le nom d'une personne, ex. "Paul" +* La température courante en °C, ex. 25.3 +* L'âge d'une personne, ex. 30 +- Affichez dans la console les valeurs de ces trois variables. + +--- + +== Exercice 2 + +- Demandez à l'utilisateur de saisir du texte, et mettez-le dans une variable +- Affichez le contenu de la variable. + +*Fonctions nécessaires* : `variable = input("Texte d'invite:")`, `print()` + +--- + +== Exercice 3 : Expressions + +- Déclarez plusieurs variables, contenant le résultats de : +* Une opération arithmétique entre nombres +* Une comparaison entre nombres +* Une opération d'addition entre deux chaînes +* L'expression `(59 * 62 + 13) / 6.5` +- Affichez leur contenu dans la console. + +--- + +== Exercice A1 : Conversion en ordres de grandeur + +- Déclarez une variable contenant une distance en mètres (au moins 1001, ex 4210) +- Affichez le nombre de kilomètres dans cette valeur (nombre entier, ex. 4) +- Afficher le nombre de mètres restants dans cette valeur (ex. 210) + +*Outils nécessaires* : opérateurs `//` (division entière), `%` (modulo) + +Vous pouvez afficher tout cela sur une ligne avec un seul appel à la fonction `print()`, par exemple : + +```python +kilometers = 5 +meters = 450 +print(kilometers, "kilomètres et", meters, "mètres.") +``` + +--- + +== Exercice A2 : Deux ordres de grandeur + +- Déclarez une variable contenant une masse en grammes (au moins 1 000 000) +- Affichez le nombre de tonnes, de kilogrammes et de grammes dans cette masse. + +Vous devrez utiliser les mêmes outils que dans l'exercice précédent, mais il +y a deux ordres de grandeur à prendre en compte ! + +--- + +== Exercice A3 : Saisie de nombres + +- Demandez à l'utilisateur de saisir deux nombres (en deux fois). +- Indiquez quel est le nombre le plus grand qui a été saisi. + +Sachant que la saisie récupérée est toujours une chaîne de caractères vous devez récupérer une version de la saisie qui est un nombre pour pouvoir faire des comparaisons intéressantes. + +*Rappel* : pour récupérer un entier depuis une chaîne, utilisez `int(valeur)` diff --git a/training/exercices/02-language-basics/03-conditions.asciidoc b/training/exercices/02-language-basics/03-conditions.asciidoc new file mode 100644 index 0000000..76377d3 --- /dev/null +++ b/training/exercices/02-language-basics/03-conditions.asciidoc @@ -0,0 +1,72 @@ += Conditions + +--- + +== Exercice 1 : `if` seul + +- Déclarez une variable avec une valeur entière entre 1 et 6 (lancer de dé). +- Affichez `"Lancer réussi !"` si la valeur est supérieure strictement à 4 +- Retestez votre code en changeant la valeur du lancer + +--- + +== Exercice 2 : `if` seul, comparer du texte + +- Déclarez une variable avec le texte `"Bonjour"`; +- Affichez `"Bien le bonjour"` si votre variable est égale à `"bonjouR"`. + +(Les majuscules ne sont pas placées ici par hasard, conservez-les) + +--- + +== Exercice 2B : `if…else` + +- Assignez à une variable le texte `"Bonjour"`; +- Affichez `"Bien le bonjour"` si votre variable est égale à `"Bonjour"`; +- Sinon, (dans tous les autres cas) afficher `"Je ne comprends pas !"`. + +--- + +== Exercice 3 : `if…elif…else` + +- Assignez à une variable un entier arbitraire entre 0 et 10 inclus; +- Si cette valeur est d'au moins 9, afficher `"Élevé"`; +- Sinon, si cette valeur est d'au moins 7, afficher `"Haut"`; +- Sinon, si cette valeur est d'au moins 4, afficher `"Standard"`; +- Sinon, afficher `"Bas"`. + +--- + +== Exercice A1 : Multiples conditions + +- Assignez à deux variables `a1` et `a2` des nombres entiers entre 0 et 10 +- Si `a1` est supérieur à 5 *et* `a2` est inférieur à 6, afficher `"OK"` +- Sinon, afficher `"Valeurs incorrectes"` + +--- + +== Exercice A2 (conditions avec `and` et `or`) + +- Assignez à deux variables `a1` *et* `a2` des nombres entre 0 et 10 +- Si `a1` est supérieur à 5 *ou* `a2` est inférieur à 6, afficher `"Conditions suffisantes"` +- Sinon, afficher `"Valeurs incorrectes"` + +--- + +== Exercice A3 + +- Déclarez une variable de statut `is_on` contenant un booléen (`True` ou `False`) +- Demandez à l'utilisateur de *saisir un texte*, et assignez-le à une variable `saisie` +- Si `saisie` vaut "Marche" : +* Si `is_on` est `False`, alors afficher "Allumage en cours..." +* Sinon, afficher "Déjà allumé !" +- Sinon, si `saisie` vaut "Arrêt" : +* Si `is_on` est `True`, afficher "Extinction..." +* Sinon, afficher "Déjà éteint !" + +Exemple de rappel : + +```python +# Demander de saisir un texte et récupérer le résultat dans une variable +saisie = input("Saisissez du texte :") +``` diff --git a/training/exercices/02-language-basics/04-empty-block.asciidoc b/training/exercices/02-language-basics/04-empty-block.asciidoc new file mode 100644 index 0000000..f76c70d --- /dev/null +++ b/training/exercices/02-language-basics/04-empty-block.asciidoc @@ -0,0 +1,6 @@ += Exercices sur les blocs vides + +== Exercice 1 + +- Écrivez un bloc `if` dont le code, lorsqu'il est exécuté, ne fait rien. +- *Outils* : `pass` diff --git a/training/exercices/02-language-basics/05-for-loop.asciidoc b/training/exercices/02-language-basics/05-for-loop.asciidoc new file mode 100644 index 0000000..d230863 --- /dev/null +++ b/training/exercices/02-language-basics/05-for-loop.asciidoc @@ -0,0 +1,17 @@ += Exercices sur les boucles `for` + +== Exercice 1 + +- Écrivez une boucle `for` sur les nombres de 0 à 9. +- Affichez la valeur du nombre parcouru. + +== Exercice 2 + +- Écrivez une boucle `for` sur les nombres de 0 à 9. +- Affichez la valeur du nombre s'il est pair (`nombre % 2 == 0`) + +== Exercice A1 + +- Écrivez une boucle `for` sur les nombres de 0 à 9 (variable nommée `item1`). +- Dans cette boucle, écrivez une autre boucle sur les nombres de 0 à `item1` (variable `item2`) +- Dans cette sous-boucle, affichez sur la même ligne `item1` et `item2`. diff --git a/training/exercices/02-language-basics/06-while-loop.asciidoc b/training/exercices/02-language-basics/06-while-loop.asciidoc new file mode 100644 index 0000000..7401096 --- /dev/null +++ b/training/exercices/02-language-basics/06-while-loop.asciidoc @@ -0,0 +1,22 @@ += Exercices sur les boucles `while` + +== Exercice 1 + +- Déclarer une variable `number` égale à 10 +- Écrivez une boucle `while` tournant tant que `number` est supérieur ou égal à 0. +- Dans la boucle, afficher `number`, et retirer `1` à `number`. + +== Exercice 2 + +- Écrire une boucle `while` qui tourne indéfiniment (condition `True`, ou soyez créatif) + +== Exercice 3 + +- Écrire une boucle `while` qui ne se lance jamais (condition `False`, ou soyez créatif) +- (il suffit que la condition soit fausse dès le départ) + +== Exercice A1 : Fibonacci + +- Écrire du code, affichant dans la console, les éléments successifs de la suite de Fibonacci jusqu'à 10 000 : +* Utiliser deux variables, `left` and `right` qui vont, au départ, contenir les deux premiers éléments de la suite. +* Dans la boucle, modifier `left` and `right` pour ne garder que les deux derniers éléments de la suite. diff --git a/training/exercices/02-language-basics/07-lists.asciidoc b/training/exercices/02-language-basics/07-lists.asciidoc new file mode 100644 index 0000000..644e896 --- /dev/null +++ b/training/exercices/02-language-basics/07-lists.asciidoc @@ -0,0 +1,60 @@ += Exercices sur les listes + +== Exercice 1 + +- Écrivez une liste contenant les nombres entiers pairs de 0 à 10 inclus +- Assignez la longueur de la liste à une variable (`len()`) +- Affichez le dernier élément de la liste (en utilisant la longueur) +- Ajoutez un élément à la fin de la liste +- Affichez le nouveau contenu de la liste + +== Exercice 2 + +- Écrivez une liste contenant les nombres 1, 2, 4, 8, 16, 32, 64 +- Supprimez de la liste le nombre 8 +- Ajoutez à la fin de la liste le nombre 128 +- Affichez le contenu de la liste dans la console. + +== Exercice 3 (indices négatifs) + +- Écrivez une liste contenant 3 éléments +- Affichez le *dernier* élément en utilisant un indice négatif +- Affichez le *premier* élément en utilisant un indice négatif + +== Pré-Exercice 4 (slicing) + +[source,python] +---- +a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +b = a[0:5] # Index 0 à 5 non inclus. Marche aussi sur les chaînes. +c = a[5:0] # L'index de fin est inférieur au départ, renvoie une liste vide +f = a[:] # Renvoie toute la liste +d = a[::-1] # Tout parcourir à l'envers +e = a[::2] # Tout parcourir 2 par 2 +---- + + +== Exercice 4 (slicing) + +- Écrivez une liste de 6 nombres +- Affichez la liste comprenant les 3 premiers éléments +- Affichez la liste comprenant tout sauf le premier élément + +== Exercice 5 (slicing avancé) + +- Réutilisez la liste de l'exercice 4 +- Affichez toute la liste, mais à l'envers +- Affichez une liste comprenant les éléments aux indices pairs + +== Exercice A1 + +- Écrivez une liste contenant les nombres multiples de 3 de 0 à 15. +- Faites une boucle `for` sur cette liste, +* et affichez uniquement les nombres pairs de cette liste (`valeur % 2 == 0`) + +== Exercice A2 + +- Consultez la https://docs.python.org/3/tutorial/datastructures.html#more-on-lists[référence des fonctions de listes] +- Déclarez une liste de nombres flottants +- Utilisez la méthode qui sert à renvoyer le dernier élément et le supprimer de la liste +- Affichez cet élément, puis la liste diff --git a/training/exercices/02-language-basics/08-sets.asciidoc b/training/exercices/02-language-basics/08-sets.asciidoc new file mode 100644 index 0000000..54960aa --- /dev/null +++ b/training/exercices/02-language-basics/08-sets.asciidoc @@ -0,0 +1,42 @@ += Exercices sur les ensembles + +== Exercice 1 + +- Écrivez un `set` contenant 5 valeurs +- Déclarez un second `set` contenant au moins 2 valeurs du premier set +- Essayez d'ajouter une valeur déjà existante à un set +- Affichez les valeurs communes aux deux sets (`intersection()`) +- Affichez un set contenant toutes les valeurs des 2 sets (`union()`) + +== Exercice 2 (conversion) + +- Écrivez une *liste* contenant des valeurs en doublons +- Affichez le contenu de la liste +- Assignez à une variable la conversion de la liste en set (`set(x)`) +- Affichez la valeur du set obtenu + +== Exercice 3 + +Al et Kim sont inscrits sur un réseau social. Al a les amis suivants : + +- Josephine +- Meghan +- Amy +- Bob + +Kim a les amis suivants : + +- Frank +- Amy +- Josephine +- Susan + +Quels sont leurs amis en commun ? Écrivez un code qui représente et résout cet énoncé. + +== Exercice 4 + +Partant du tuple suivant : + +`(1, 4, 6, 9, 1, 3, 6, 12, 2, 5, 7, 10, 3, 5, 2, 6, 4, 6, 1, 8, 5, 2, 3, 6)` + +- Affichez le nombre de valeurs différentes présentes dans le tuple. diff --git a/training/exercices/02-language-basics/09-dictionaries.asciidoc b/training/exercices/02-language-basics/09-dictionaries.asciidoc new file mode 100644 index 0000000..3be21a1 --- /dev/null +++ b/training/exercices/02-language-basics/09-dictionaries.asciidoc @@ -0,0 +1,40 @@ += Exercices sur les dictionnaires + +== Exercice 1 + +- Écrivez un simple dictionnaire associant des noms à des âges : +* Paul → 30 +* Karim → 22 +* Gina → 41 +* Anna → 25 +- Affichez l'âge de Gina +- Ajoutez les associations suivantes : +* Alina → 33 +* Victor → 55 +- Affichez le contenu du dictionnaire + +== Exercice 2 (parcours) + +- Réutilisez votre dictionnaire +- Utilisez une boucle `for` normale pour : +* Afficher les clés du dictionnaire +* Afficher la valeur associée à chaque clé + +== Exercice 3 (parcours + `.items()`) + +- Réutilisez votre dictionnaire +- Utilisez une boucle `for` sur `.items()` avec deux variables : +* Affichez clé et valeur associée + +== Exercice A1 (compréhension) + +- Déclarez un dictionnaire de conditions météo (°C, condition, pression) +* `meteo = {"Pau": (21.0, "Nuageux", 1015), "Gap": (20.3, "Dégagé", 1019), "Osny": (19.1, "Brouillard", 1015)}` +- À l'aide d'une compréhension de dictionnaire, récupérer un dictionnaire : +* Dont les clés sont les mêmes noms de villes +* Dont les valeurs sont uniquement la température associée + +== Exercice A2 (compréhensions) + +- Déclarez une liste via une compréhension, qui contient les nombres pairs de 0 à 98, sauf ceux divisibles par 5. (comprendre, uniquement ceux non divisibles par 5). +- Déclarez une liste de mots manuellement. Puis déclarez un générateur (compréhension de tuple) qui contient uniquement les mots de plus de 4 lettres. (`len()`). diff --git a/training/exercices/02-language-basics/10-strings.asciidoc b/training/exercices/02-language-basics/10-strings.asciidoc new file mode 100644 index 0000000..3488e5a --- /dev/null +++ b/training/exercices/02-language-basics/10-strings.asciidoc @@ -0,0 +1,48 @@ += Exercices sur les manipulations de chaînes + +== Exercice 1 + +- Consultez https://docs.python.org/3/library/stdtypes.html#string-methods[les méthodes disponibles sur les chaînes] +- Déclarez une chaîne de caractères avec plusieurs mots +- Affichez la version tout en majuscules (`upper`) +- Affichez la version tout en minuscules (`lower`) +- Découpez la autour des espaces (`split`) + +== Exercice 2 (joindre les deux bouts) + +- Partant de cette liste de mots : + +[source,python] +---- +word_list = ("mon", "vieux", "tonton", "m'a", "jeté", "sur", "une", "nouvelle", "planète") +---- + +Utiliser la méthode `join()` sur une chaîne de séparation pour reconstituer la phrase entière. +(N'utilisez pas de boucle `for`). + +== Exercice 3 (slicing) + +- Déclarez une chaîne de caractères quelconque +- En utilisant le _slicing_, affichez-la à l'envers +- De la même façon, affichez uniquement les 5 premiers caractères +- Affichez le texte, mais uniquement un caractère sur deux + +== Exercice 4 (f-strings) + +- Déclarez plusieurs variables : +* `number = 14` +* `base_list = [1, 2, 3]` +- Affichez une *f-string* incluant le contenu de `number` et `base_list` : +* Il est *14* heures. La liste est *[1, 2, 3]*. + +== Exercice A1 (`join` + conversion) + +Partant de cette liste : + +[source, python] +---- +items = ["Hello, it's", True, "that", 40, "people have", None] +---- + +- Confectionner une phrase avec `" ".join()`. +- La fonction `join` nécessitant une liste de chaînes pour fonctionner, utilisez une compréhension de liste pour convertir cette liste en liste de chaînes (utilisez `str(x)`). diff --git a/training/exercices/03-exceptions/01-exceptions.asciidoc b/training/exercices/03-exceptions/01-exceptions.asciidoc new file mode 100644 index 0000000..866385c --- /dev/null +++ b/training/exercices/03-exceptions/01-exceptions.asciidoc @@ -0,0 +1,37 @@ += Exercices sur les exceptions + +== Exercice 1 + +- Écrivez un bloc `try/except` +- Dans le bloc `try`, provoquez une division par zéro (`ZeroDivisionError`) +- Dans le bloc `except`, affichez "Division impossible !" + +== Exercice A1 + +- Générez un nombre entier aléatoire entre 0 et 1 : + +[source,python] +---- +from random import randint +number = randint(0, 1) +---- + +- Écrivez un bloc `try/except` +- Dans le bloc `try` : +* Si `number` vaut `0`, afficher `[1, 2, 3][4]` (`IndexError`) +* Si `number` vaut `1`, afficher `{}[0]` (`KeyError`) +- Écrire un bloc `except` pour `IndexError`, qui affiche "Erreur d'index" +- Écrire un bloc `except` pour `KeyError`, qui affiche "Erreur de clé" + +== Exercice A2 (variante) + +- Reprenez une copie de l'exercice 1 +- Mais cette fois, ayez un seul bloc `except` qui gère à la fois `IndexError` et `KeyError`, et qui affiche "Erreur d'accès". + +== Exercice A3 + +- Écrivez un bloc `try/except` +- Provoquez une erreur dans le bloc `try` (pas une erreur de syntaxe !) +- Écrivez un bloc `except` qui ne gère pas la bonne erreur (ex. `IOError`) +- Écrivez un bloc `finally` qui affiche du texte +- Exécutez votre code et voyez que le bloc `finally` est bien honoré. diff --git a/training/exercices/04-functions/01-base.asciidoc b/training/exercices/04-functions/01-base.asciidoc new file mode 100644 index 0000000..0a9f703 --- /dev/null +++ b/training/exercices/04-functions/01-base.asciidoc @@ -0,0 +1,37 @@ += Exercices sur les fonctions + +== Exercice 1 + +- Écrivez une fonction nommée `show_something` qui ne prend pas d'argument +- Cette fonction doit afficher dans la console "Something" +- Appelez cette fonction + +== Exercice 2 + +- Écrivez une fonction nommée `return_constant` qui ne prend pas d'argument +- Cette fonction affiche dans la console "99" +- Cette fonction renvoie à l'appelant la valeur `99` +- Appeler la fonction et assigner sa valeur de retour à une variable +- Afficher le contenu de la variable + +== Exercice 3 + +- Écrivez une fonction nommée `product` qui prend deux arguments positionnels `x` et `y` +- Cette fonction renvoie le produit de `x` et `y` +- Affichez le résultat de cette fonction lorsque vous l'appelez avec les valeurs : +* `10, 10` +* `15, -15` +* `"hello ", 3` +* `[1, 2, 3], 2` + +== Exercice 4 + +- Écrivez une fonction nommée `quotient` qui prend un argument positionnel `numerator` et un argument par défaut `denominator`, qui prend la valeur `1` par défaut. +- La fonction renvoie le quotient de `numerator` et `denominator`. +- La fonction gère l'exception de `ZeroDivisionError` en renvoyant la valeur `None`. +- Affichez le résultat de cette fonction lorsque vous l'appelez avec les valeurs : +* `10, 4` +* `10, -1` +* `1, 0` +* `10` +- Variez les appels en passant les arguments positionnellement, par nom, etc. diff --git a/training/exercices/04-functions/02-advanced-args.asciidoc b/training/exercices/04-functions/02-advanced-args.asciidoc new file mode 100644 index 0000000..43c3dac --- /dev/null +++ b/training/exercices/04-functions/02-advanced-args.asciidoc @@ -0,0 +1,19 @@ += Exercices sur les fonctions + +== Exercice A1 + +- Écrivez une fonction `print_lines` qui prend un argument étoile `*lines` +- La fonction utilise une boucle `for` pour afficher les éléments de `lines` dans la console +- Appelez la fonction avec des arguments différents : +* `"ligne 1", "ligne 2", 13, 14, 15` +* _aucun argument_ +* `"matin", "midi", "soir", "nuit"` + +== Exercice A2 + +- Écrivez une fonction `mappings` qui prend un argument double-étoile `**prices` +- La fonction parcourt le dictionnaire dans `prices` et affiche pour chaque clé `key` : +* `f"Produit : {key:<16} - Prix : {value:.2f}€"` +- Testez l'appel de cette fonction avec des arguments suivants : +* `pomme=0.8, cassis=1.5, ananas=2.8, raisin=4.99` +* `perrier=1.2, badoit=0.95, san_pellegrino=1.1, vichy=40` diff --git a/training/exercices/06-extra-types/01-datetime.asciidoc b/training/exercices/06-extra-types/01-datetime.asciidoc new file mode 100644 index 0000000..436a5b5 --- /dev/null +++ b/training/exercices/06-extra-types/01-datetime.asciidoc @@ -0,0 +1,30 @@ += Exercices sur les dates et heures + +== Exercice 1 + +- Déclarez trois objets `datetime` : +* `now` : là, tout de suite +* `forty_ago` : le 12 février 1981 à 22h31 +* `fifteen_ago` : le 3 mars 2006 à 16h10 et 14 secondes +- Affichez chacun de ces objets dans la console +- Affichez le mois de `forty_ago` (`.month`) +- Affichez les minutes et secondes de `fifteen_ago` + +== Exercice 2 + +- Conservez les variables du dessus +- Assignez la différence entre `now` et `forty_ago` dans une variable `interval_40` +- Affichez le nombre de jours contenus dans `interval_40` (`.days`) +- Affichez la date qu'il sera dans `interval_40` (`now + interval_40`) + +== Exercice 3 (conversion vers chaîne) + +- Conservez les variables du dessus +- Affichez `fifteen_ago` sous la forme suivante : +* `"03 mars 2006, 16:10:14"` +- (utilisez `fifteen_ago.strftime(format 8563.3.3.)`) + +== Exercice 4 (conversion depuis chaîne) + +- Convertissez la chaîne `"31-01-2019 16:48"` vers un objet `datetime` +- (utilisez `datetime.strptime(chaine, format)`) diff --git a/training/exercices/07-objects/01-base-class.asciidoc b/training/exercices/07-objects/01-base-class.asciidoc new file mode 100644 index 0000000..39c81ce --- /dev/null +++ b/training/exercices/07-objects/01-base-class.asciidoc @@ -0,0 +1,57 @@ += Exercices sur les classes (basique) + +== Exercice 1 + +(Thème *bibliothèque*) + +- Déclarez une classe `Library` +- Avec un attribut `name` (défaut `None`) +- Avec un attribut `address` (défaut `None`) +- Instanciez deux nouveaux objets de cette classe (différenciez noms de variables et de classes) +- Affichez la valeur de l'attribut `name` de l'un des objets + +== Exercice 2 + +- Déclarez une classe `Book` +- Avec des attributs `title` (`None`), `author` (`None`), `year` (`None`) +- Instanciez un nouvel objet de cette classe +- Modifiez les attributs `title` et `author` +- Affichez la valeur de ces attributs + +== Exercice 3 (méthodes) + +- Réutilisez la classe `Library` +- Ajoutez-y un attribut `is_open` (`True`) +- Ajoutez une méthode `open(value=True)` qui change l'attribut `is_open` +- Ajoutez une méthode `show_status()` qui affiche l'état de la bibliothèque : +* `"Bibliothèque :"` +* `"État : Ouverte"` (ou `"fermée"`) + +== Exercice 4 (Redéfinition de l'instanciation) + +- Réutilisez la classe `Library` +- Définissez la méthode `_ _ init _ _()`, qui accepte des arguments `name` et `address` : +* `name` est un argument à valeur par défaut, à `None` +* `address` possède une valeur par défaut à `None` +* La méthode utilise ces arguments pour initialiser les attributs de `self`. +- Instanciez deux nouveaux objets de cette classe +- Exécutez la méthode `show_status()` sur ces deux objets + +== Exercice 5 (Héritage) + +- Définissez une classe `ComicBook` héritant de `Book` +- Cette classe contient en plus un attribut `is_color` (`True`) +- Instanciez un objet de chacune des deux classes `Book` et `ComicBook` +- Vérifiez que l'objet de type `ComicBook` est bien un `Book` : +* en utilisant la fonction `isinstance(object, class)` + +== Exercice 6 (Polymorphisme) + +- Ajoutez un attribut `is_published` sur la classe `Book` +- Ajoutez une méthode `publish(value)` sur `Book`, qui change l'attribut `is_published` +- Redéfinissez la méthode `publish(value)` sur `ComicBook`, qui fait la même chose que dans `Book` (fonction `super()`), puis affiche `"Comic book mis à jour"` +- Testez les méthodes sur deux objets, de type `Book` et `ComicBook`. + +== Exercice B1 (staticmethod) + +- Écrivez une méthode statique dont la syntaxe est correcte. diff --git a/training/exercices/08-text-files/01-text.asciidoc b/training/exercices/08-text-files/01-text.asciidoc new file mode 100644 index 0000000..d981dd8 --- /dev/null +++ b/training/exercices/08-text-files/01-text.asciidoc @@ -0,0 +1,34 @@ += Exercices sur les fichiers texte + +== Exercice 1 + +- Écrivez un fichier texte, dans lequel vous écrivez les lignes suivantes : +* `Il est un feu discret qui se cache en ton âme,` +* `Mais qui tremble et palpite à tous les coups du sort :` +* `C'est l'espoir ! Défends bien cette petite flamme ;` +* `Si la flamme s'éteint, ami, ton cœur est mort.` +- Pensez bien aux `"\n"` pour passer à la ligne ! + +== Exercice 2 + +- Ouvrez à nouveau votre fichier texte, mais en lecture +- Pour relire et afficher les lignes du fichier une à une +- Utilisez une boucle `while` : +* `line = ` +* `while line != "":` +* `` +* `` + +ou + +- Variante de boucle avec la syntaxe de `Python 3.8` +* `while line := :` +* + +== Exercice 3 (ouverture avec `with`) + +- Remplacez le code des deux exercices précédents pour utiliser un gestionnaire de contexte. + + + + diff --git a/training/exercices/08-text-files/02-text-formats.asciidoc b/training/exercices/08-text-files/02-text-formats.asciidoc new file mode 100644 index 0000000..9c5ce78 --- /dev/null +++ b/training/exercices/08-text-files/02-text-formats.asciidoc @@ -0,0 +1,39 @@ += Exercices sur les fichiers texte JSON, CSV etc. + +== Exercice 1 (JSON) + +- Convertissez le contenu du fichier JSON proposé sur le dépôt Git en structure Python +- La donnée lue depuis le fichier JSON contient un dictionnaire +* Quelle notation d'accès aux données du dictionnaire allez-vous utiliser pour récupérer la valeur suivante ? +* `"New York Bulls"` +- Indice : `data["quiz"]["sport"]...` + +== Exercice 2 (JSON, écriture) + +- Créez une structure Python étant une liste ou un dictionnaire +- Écrivez un fichier JSON valide depuis cette structure +- Le fichier doit être indenté (`json.dumps(data, indent=4)`) + +== Exercice 3 (CSV) + +- Ouvrez à nouveau votre fichier texte, mais en lecture +- Pour relire et afficher les lignes du fichier une à une +- Utilisez une boucle `while` : +* `line = ` +* `while line != "":` +* `` +* `` + +ou + +- Variante de boucle avec la syntaxe de `Python 3.8` +* `while line := :` +* + +== Exercice 3 (ouverture avec `with`) + +- Remplacez le code des deux exercices précédents pour utiliser un gestionnaire de contexte. + + + + diff --git a/training/exercices/08-text-files/demo-file.csv b/training/exercices/08-text-files/demo-file.csv new file mode 100644 index 0000000..65b43f5 --- /dev/null +++ b/training/exercices/08-text-files/demo-file.csv @@ -0,0 +1,100 @@ +1,"Eldon Base for stackable storage shelf, platinum",Muhammed MacIntyre,3,-213.25,38.94,35,Nunavut,Storage & Organization,0.8 +2,"1.7 Cubic Foot Compact ""Cube"" Office Refrigerators",Barry French,293,457.81,208.16,68.02,Nunavut,Appliances,0.58 +3,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Barry French,293,46.71,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +4,R380,Clay Rozendal,483,1198.97,195.99,3.99,Nunavut,Telephones and Communication,0.58 +5,Holmes HEPA Air Purifier,Carlos Soltero,515,30.94,21.78,5.94,Nunavut,Appliances,0.5 +6,G.E. Longer-Life Indoor Recessed Floodlight Bulbs,Carlos Soltero,515,4.43,6.64,4.95,Nunavut,Office Furnishings,0.37 +7,"Angle-D Binders with Locking Rings, Label Holders",Carl Jackson,613,-54.04,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +8,"SAFCO Mobile Desk Side File, Wire Frame",Carl Jackson,613,127.70,42.76,6.22,Nunavut,Storage & Organization, +9,"SAFCO Commercial Wire Shelving, Black",Monica Federle,643,-695.26,138.14,35,Nunavut,Storage & Organization, +10,Xerox 198,Dorothy Badders,678,-226.36,4.98,8.33,Nunavut,Paper,0.38 +11,Xerox 1980,Neola Schneider,807,-166.85,4.28,6.18,Nunavut,Paper,0.4 +12,Advantus Map Pennant Flags and Round Head Tacks,Neola Schneider,807,-14.33,3.95,2,Nunavut,Rubber Bands,0.53 +13,Holmes HEPA Air Purifier,Carlos Daly,868,134.72,21.78,5.94,Nunavut,Appliances,0.5 +14,"DS/HD IBM Formatted Diskettes, 200/Pack - Staples",Carlos Daly,868,114.46,47.98,3.61,Nunavut,Computer Peripherals,0.71 +15,"Wilson Jones 1"" Hanging DublLock Ring Binders",Claudia Miner,933,-4.72,5.28,2.99,Nunavut,Binders and Binder Accessories,0.37 +16,Ultra Commercial Grade Dual Valve Door Closer,Neola Schneider,995,782.91,39.89,3.04,Nunavut,Office Furnishings,0.53 +17,"#10-4 1/8"" x 9 1/2"" Premium Diagonal Seam Envelopes",Allen Rosenblatt,998,93.80,15.74,1.39,Nunavut,Envelopes,0.4 +18,Hon 4-Shelf Metal Bookcases,Sylvia Foulston,1154,440.72,100.98,26.22,Nunavut,Bookcases,0.6 +19,"Lesro Sheffield Collection Coffee Table, End Table, Center Table, Corner Table",Sylvia Foulston,1154,-481.04,71.37,69,Nunavut,Tables,0.68 +20,g520,Jim Radford,1344,-11.68,65.99,5.26,Nunavut,Telephones and Communication,0.59 +21,LX 788,Jim Radford,1344,313.58,155.99,8.99,Nunavut,Telephones and Communication,0.58 +22,Avery 52,Carlos Soltero,1412,26.92,3.69,0.5,Nunavut,Labels,0.38 +23,Plymouth Boxed Rubber Bands by Plymouth,Carlos Soltero,1412,-5.77,4.71,0.7,Nunavut,Rubber Bands,0.8 +24,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Carl Ludwig,1539,-172.88,15.99,13.18,Nunavut,Binders and Binder Accessories,0.37 +25,"Maxell 3.5"" DS/HD IBM-Formatted Diskettes, 10/Pack",Carl Ludwig,1539,-144.55,4.89,4.93,Nunavut,Computer Peripherals,0.66 +26,Newell 335,Don Miller,1540,5.76,2.88,0.7,Nunavut,Pens & Art Supplies,0.56 +27,SANFORD Liquid Accent Tank-Style Highlighters,Annie Cyprus,1702,4.90,2.84,0.93,Nunavut,Pens & Art Supplies,0.54 +28,Canon PC940 Copier,Carl Ludwig,1761,-547.61,449.99,49,Nunavut,Copiers and Fax,0.38 +29,"Tenex Personal Project File with Scoop Front Design, Black",Carlos Soltero,1792,-5.45,13.48,4.51,Nunavut,Storage & Organization,0.59 +30,Col-Erase Pencils with Erasers,Grant Carroll,2275,41.67,6.08,1.17,Nunavut,Pens & Art Supplies,0.56 +31,"Imation 3.5"" DS/HD IBM Formatted Diskettes, 10/Pack",Don Miller,2277,-46.03,5.98,4.38,Nunavut,Computer Peripherals,0.75 +32,"White Dual Perf Computer Printout Paper, 2700 Sheets, 1 Part, Heavyweight, 20 lbs., 14 7/8 x 11",Don Miller,2277,33.67,40.99,19.99,Nunavut,Paper,0.36 +33,Self-Adhesive Address Labels for Typewriters by Universal,Alan Barnes,2532,140.01,7.31,0.49,Nunavut,Labels,0.38 +34,Accessory37,Alan Barnes,2532,-78.96,20.99,2.5,Nunavut,Telephones and Communication,0.81 +35,Fuji 5.2GB DVD-RAM,Jack Garza,2631,252.66,40.96,1.99,Nunavut,Computer Peripherals,0.55 +36,Bevis Steel Folding Chairs,Julia West,2757,-1766.01,95.95,74.35,Nunavut,Chairs & Chairmats,0.57 +37,Avery Binder Labels,Eugene Barchas,2791,-236.27,3.89,7.01,Nunavut,Binders and Binder Accessories,0.37 +38,Hon Every-Day Chair Series Swivel Task Chairs,Eugene Barchas,2791,80.44,120.98,30,Nunavut,Chairs & Chairmats,0.64 +39,"IBM Multi-Purpose Copy Paper, 8 1/2 x 11"", Case",Eugene Barchas,2791,118.94,30.98,5.76,Nunavut,Paper,0.4 +40,Global Troy Executive Leather Low-Back Tilter,Edward Hooks,2976,3424.22,500.98,26,Nunavut,Chairs & Chairmats,0.6 +41,XtraLife ClearVue Slant-D Ring Binders by Cardinal,Brad Eason,3232,-11.83,7.84,4.71,Nunavut,Binders and Binder Accessories,0.35 +42,Computer Printout Paper with Letter-Trim Perforations,Nicole Hansen,3524,52.35,18.97,9.03,Nunavut,Paper,0.37 +43,6160,Dorothy Wardle,3908,-180.20,115.99,2.5,Nunavut,Telephones and Communication,0.57 +44,Avery 49,Aaron Bergman,4132,1.32,2.88,0.5,Nunavut,Labels,0.36 +45,Hoover Portapower Portable Vacuum,Jim Radford,4612,-375.64,4.48,49,Nunavut,Appliances,0.6 +46,Timeport L7089,Annie Cyprus,4676,-104.25,125.99,7.69,Nunavut,Telephones and Communication,0.58 +47,Avery 510,Annie Cyprus,4676,85.96,3.75,0.5,Nunavut,Labels,0.37 +48,Xerox 1881,Annie Cyprus,4676,-8.38,12.28,6.47,Nunavut,Paper,0.38 +49,LX 788,Annie Cyprus,4676,1115.69,155.99,8.99,Nunavut,Telephones and Communication,0.58 +50,"Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl",Annie Cyprus,5284,-3.05,8.69,2.99,Nunavut,Binders and Binder Accessories,0.39 +51,"Memorex 4.7GB DVD-RAM, 3/Pack",Clay Rozendal,5316,514.07,31.78,1.99,Nunavut,Computer Peripherals,0.42 +52,Unpadded Memo Slips,Don Jones,5409,-7.04,3.98,2.97,Nunavut,Paper,0.35 +53,"Adams Telephone Message Book W/Dividers/Space For Phone Numbers, 5 1/4""X8 1/2"", 300/Messages",Beth Thompson,5506,4.41,5.88,3.04,Nunavut,Paper,0.36 +54,"Eldon Expressions Desk Accessory, Wood Pencil Holder, Oak",Frank Price,5569,-0.06,9.65,6.22,Nunavut,Office Furnishings,0.55 +55,Bell Sonecor JB700 Caller ID,Michelle Lonsdale,5607,-50.33,7.99,5.03,Nunavut,Telephones and Communication,0.6 +56,Avery Arch Ring Binders,Ann Chong,5894,87.68,58.1,1.49,Nunavut,Binders and Binder Accessories,0.38 +57,APC 7 Outlet Network SurgeArrest Surge Protector,Ann Chong,5894,-68.22,80.48,4.5,Nunavut,Appliances,0.55 +58,"Deflect-o RollaMat Studded, Beveled Mat for Medium Pile Carpeting",Joy Bell,5925,-354.90,92.23,39.61,Nunavut,Office Furnishings,0.67 +59,Accessory4,Joy Bell,5925,-267.01,85.99,0.99,Nunavut,Telephones and Communication,0.85 +60,Personal Creations Ink Jet Cards and Labels,Skye Norling,6016,3.63,11.48,5.43,Nunavut,Paper,0.36 +61,High Speed Automatic Electric Letter Opener,Barry Weirich,6116,-1759.58,1637.53,24.49,Nunavut,"Scissors, Rulers and Trimmers",0.81 +62,Xerox 1966,Grant Carroll,6182,-116.79,6.48,6.65,Nunavut,Paper,0.36 +63,Xerox 213,Grant Carroll,6182,-67.28,6.48,7.86,Nunavut,Paper,0.37 +64,"Boston Electric Pencil Sharpener, Model 1818, Charcoal Black",Adrian Hane,6535,-19.33,28.15,8.99,Nunavut,Pens & Art Supplies,0.57 +65,Hammermill CopyPlus Copy Paper (20Lb. and 84 Bright),Skye Norling,6884,-61.21,4.98,4.75,Nunavut,Paper,0.36 +66,"Telephone Message Books with Fax/Mobile Section, 5 1/2"" x 3 3/16""",Skye Norling,6884,119.09,6.35,1.02,Nunavut,Paper,0.39 +67,Crate-A-Files,Andrew Gjertsen,6916,-141.27,10.9,7.46,Nunavut,Storage & Organization,0.59 +68,"Angle-D Binders with Locking Rings, Label Holders",Ralph Knight,6980,-77.28,7.3,7.72,Nunavut,Binders and Binder Accessories,0.38 +69,"80 Minute CD-R Spindle, 100/Pack - Staples",Dorothy Wardle,6982,407.44,39.48,1.99,Nunavut,Computer Peripherals,0.54 +70,"Bush Westfield Collection Bookcases, Dark Cherry Finish, Fully Assembled",Dorothy Wardle,6982,-338.27,100.98,57.38,Nunavut,Bookcases,0.78 +71,12-1/2 Diameter Round Wall Clock,Dorothy Wardle,6982,52.56,19.98,10.49,Nunavut,Office Furnishings,0.49 +72,SAFCO Arco Folding Chair,Grant Carroll,7110,1902.24,276.2,24.49,Nunavut,Chairs & Chairmats, +73,"#10 White Business Envelopes,4 1/8 x 9 1/2",Barry Weirich,7430,353.20,15.67,1.39,Nunavut,Envelopes,0.38 +74,3M Office Air Cleaner,Beth Paige,7906,271.78,25.98,5.37,Nunavut,Appliances,0.5 +75,"Global Leather and Oak Executive Chair, Black",Sylvia Foulston,8391,-268.36,300.98,64.73,Nunavut,Chairs & Chairmats,0.56 +76,Xerox 1936,Nicole Hansen,8419,70.39,19.98,5.97,Nunavut,Paper,0.38 +77,Xerox 214,Nicole Hansen,8419,-86.62,6.48,7.03,Nunavut,Paper,0.37 +78,Carina Double Wide Media Storage Towers in Natural & Black,Nicole Hansen,8833,-846.73,80.98,35,Nunavut,Storage & Organization,0.81 +79,Staples General Use 3-Ring Binders,Beth Paige,8995,8.05,1.88,1.49,Nunavut,Binders and Binder Accessories,0.37 +80,Xerox 1904,Beth Paige,8995,-78.02,6.48,5.86,Northwest Territories,Paper,0.36 +81,Luxo Professional Combination Clamp-On Lamps,Beth Paige,8995,737.94,102.3,21.26,Northwest Territories,Office Furnishings,0.59 +82,Xerox 217,Beth Paige,8995,-191.28,6.48,8.19,Northwest Territories,Paper,0.37 +83,Revere Boxed Rubber Bands by Revere,Beth Paige,8995,-21.49,1.89,0.76,Northwest Territories,Rubber Bands,0.83 +84,"Acco Smartsocket Table Surge Protector, 6 Color-Coded Adapter Outlets",Sylvia Foulston,9126,884.08,62.05,3.99,Northwest Territories,Appliances,0.55 +85,"Tennsco Snap-Together Open Shelving Units, Starter Sets and Add-On Units",Bryan Davis,9127,-329.49,279.48,35,Northwest Territories,Storage & Organization,0.8 +86,Hon 4070 Series Pagoda Round Back Stacking Chairs,Joy Bell,9509,2825.15,320.98,58.95,Northwest Territories,Chairs & Chairmats,0.57 +87,Xerox 1887,Joy Bell,9509,2.13,18.97,5.21,Northwest Territories,Paper,0.37 +88,Xerox 1891,Joy Bell,9509,707.15,48.91,5.81,Northwest Territories,Paper,0.38 +89,Avery 506,Alan Barnes,9763,75.13,4.13,0.5,Northwest Territories,Labels,0.39 +90,"Bush Heritage Pine Collection 5-Shelf Bookcase, Albany Pine Finish, *Special Order",Grant Carroll,9927,-270.63,140.98,53.48,Northwest Territories,Bookcases,0.65 +91,"Lifetime Advantage Folding Chairs, 4/Carton",Grant Carroll,9927,3387.35,218.08,18.06,Northwest Territories,Chairs & Chairmats,0.57 +92,Microsoft Natural Multimedia Keyboard,Grant Carroll,9927,-82.16,50.98,6.5,Northwest Territories,Computer Peripherals,0.73 +93,"Staples Wirebound Steno Books, 6"" x 9"", 12/Pack",Delfina Latchford,10022,-3.88,10.14,2.27,Northwest Territories,Paper,0.36 +94,"GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2"" x 11""",Don Jones,10437,-191.22,15.99,13.18,Northwest Territories,Binders and Binder Accessories,0.37 +95,Bevis Boat-Shaped Conference Table,Doug Bickford,10499,31.21,262.11,62.74,Northwest Territories,Tables,0.75 +96,"Linden 12"" Wall Clock With Oak Frame",Doug Bickford,10535,-44.14,33.98,19.99,Northwest Territories,Office Furnishings,0.55 +97,Newell 326,Doug Bickford,10535,-0.79,1.76,0.7,Northwest Territories,Pens & Art Supplies,0.56 +98,Prismacolor Color Pencil Set,Jamie Kunitz,10789,76.42,19.84,4.1,Northwest Territories,Pens & Art Supplies,0.44 +99,Xerox Blank Computer Paper,Anthony Johnson,10791,93.36,19.98,5.77,Northwest Territories,Paper,0.38 +100,600 Series Flip,Ralph Knight,10945,4.22,95.99,8.99,Northwest Territories,Telephones and Communication,0.57 diff --git a/training/exercices/08-text-files/demo-file.json b/training/exercices/08-text-files/demo-file.json new file mode 100644 index 0000000..d729b76 --- /dev/null +++ b/training/exercices/08-text-files/demo-file.json @@ -0,0 +1,38 @@ +{ + "quiz": { + "sport": { + "q1": { + "question": "Which one is correct team name in NBA?", + "options": [ + "New York Bulls", + "Los Angeles Kings", + "Golden State Warriros", + "Huston Rocket" + ], + "answer": "Huston Rocket" + } + }, + "maths": { + "q1": { + "question": "5 + 7 = ?", + "options": [ + "10", + "11", + "12", + "13" + ], + "answer": "12" + }, + "q2": { + "question": "12 - 8 = ?", + "options": [ + "1", + "2", + "3", + "4" + ], + "answer": "4" + } + } + } +} \ No newline at end of file diff --git a/training/exercices/extra-initiation/library.asciidoc b/training/exercices/extra-initiation/library.asciidoc new file mode 100644 index 0000000..dba0b1f --- /dev/null +++ b/training/exercices/extra-initiation/library.asciidoc @@ -0,0 +1,81 @@ += Atelier sur la première partie + +L'atelier suivant vous fait construire une structure où vous pouvez : + +- créer des bibliothèques +- créer des livres +- créer des utilisateurs + +Et avec ces objets, vous pouvez : + +- ajouter des livres à vos bibliothèques +- emprunter et rendre des livres +- voir les informations sur les emprunts +- voir les informations sur les livres présents dans une bibliothèque +- etc. + +L'exercice, qui peut vous prendre un peu de temps, vous permet de : + +- manipuler des objets, listes, dictionnaires +- utiliser des f-strings pour afficher des informations en console +- utiliser des méthodes et même découvrir la méthode `_ _ str _ _` (faites une recherche Google) +- structurer un peu votre code (concept limité par la taille de l'exercice) + +== Organisation + +- un package `entities` contenant +* un module `library` pour y mettre la classe `Library` +* un module `book` pour y mettre la classe `Book` +* un module `user` pour y mettre la classe `User` +- un module `application` vous servant de point d'entrée + +l'organisation est simple, ceci dû à la taille du projet. Des projets grandissants impliquent souvent des réorganisations. + +== Des bibliothèques + +. Créez une classe `Library` +. Avec des attributs +- `name` (`None`) +- `is_open` (`True`) +- `books` (`None`) +. Avec des méthodes +. `_ _ init _ _(self, name=None, is_open=True)` qui initialise les attributs du nouvel objet. +. `open(self, value=True)` pour changer l'état d'ouverture : +- Ne fait rien si `value` a déjà la même valeur que `self.is_open` +. `register_book(self, book)` qui ajoute un livre à l'attribut `.books` (le transforme d'abord en liste s'il est à `None`, puis ajoute le livre) +. `show_books()` qui affiche la liste des livres enregistrés +. `_ _ str _ _(self)` qui renvoie le texte affiché si on fait `print()` sur l'objet +. `get_book_avg_prices()` qui renvoie le prix moyen des livres de la bibliothèque + +== Des livres + +. Créez une classe `Book` +. Avec des attributs +- `title` (`None`) +- `author` (`None`) +- `is_borrowed` (`False`) : le livre est-il emprunté +- `borrower` (`None`) : personne qui a emprunté +- `history` (`None`) : liste des opérations d'emprunt du livre +- `price` (`0`) : prix de base +. Avec des méthodes +. `_ _ init _ _(self, ...)` pour initialiser les attributs `title`, `price` et `author` +. `borrow(self, user)` qui marque le livre comme emprunté, et modifie `borrower` : +- Ne fait rien si le livre est déjà marqué emprunté, sinon : +- `is_borrowed` devient `True` +- `borrower` prend la référence de l'objet de la classe `User` +- `history` *devient* une liste à laquelle on ajoute le dictionnaire `{"user": user, "when": datetime.now()}` +. `return_borrow(self)` qui marque le livre comme rendu (non emprunté) +- Ne fait rien si le livre est déjà marqué comme non emprunté, sinon : +- `borrower` prend la valeur `None` +. `show_history(self)` qui affiche l'historique formaté des emprunts +. `show_status(self)` qui affiche le statut du livre : titre, emprunté etc. + + +== Des utilisateurs + +. Créez une classe `User` +. Avec des attributs +- `name` (`None`) +. Avec des méthodes +. `_ _ init _ _(self, name=None)` qui initialise l'attribut de l'objet +. `_ _ str _ _ (self)` qui renvoie une chaîne `f"Utilisateur : {self.name}"` diff --git a/training/questions/02.language-basics/01.variables-expressions.md b/training/questions/02.language-basics/01.variables-expressions.md new file mode 100644 index 0000000..5bc36ac --- /dev/null +++ b/training/questions/02.language-basics/01.variables-expressions.md @@ -0,0 +1,30 @@ +# Variables et expressions + +---- + +Vous avez devant vous un adhérent de la librairie. +Il souhaite acheter 3 livres : + +- La fable du marronnier (19,95€) +- Python pour les débutants (49,95€) +- Guide de Sao Paulo (12,00€) + +Le livre Python pour les débutants bénéficie d'une réduction de 20% sur son prix. +Affichez un récapitulatif du reçu d'achat en stockant dans des variables les titres +des livres et leurs prix. + +Le reçu peut ressembler à cela : + +``` +Bookie Dans SAS + +Reçu +- La fable du marronnier 19.95 +- Python pour les débutants 49.95 +- Guide de Sao Paulo 12 +Réduction +- Python pour les débutants + +Total + +```